Problème: L'interface de Stateless Functional Component
est donnée comme
interface SFC<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
propTypes?: ValidationMap<P>;
}
Le type de prop de mon composant est également générique:
interface Prop<V>{
num: V;
}
Comment définir correctement mon composant? comme:
const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
donne une erreur à character 27
que Cannot find name 'T'
Voici: TypeScript Playground de l'exemple modifié
MyFindings:
1: TypeScript 2.9.1 prend en charge le composant générique avec état: http://www.typescriptlang.org/docs/handbook/release-notes/TypeScript-2-9.html#generic-type-arguments-in-jsx-elements
class myCom<T> extends React.Component<Prop<T>, any> {
render() {
return <div>test</div>;
}
}
2: Étendre SFC
pour créer une nouvelle interface, comme indiqué dans la réponse suivante, définirait le type prop du composant comme suit: any
: TypeScript Fonction sans état avec les paramètres/types de retour génériques que je ne souhaite pas. Je veux donner le bon type pour mon accessoire
Vous ne pouvez pas utiliser de génériques comme ceci:
const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
La spécification TypeScript déclare:
Une construction de la forme
< T > ( ... ) => { ... }
pourrait être analysé comme une expression de fonction de flèche avec un paramètre de type ou une assertion de type appliquée à une fonction de flèche sans paramètre de type.
la source; Microsoft/TypeScript spec.md
Votre déclaration ne correspond pas au modèle défini dans la spécification TypeScript, elle ne fonctionnera donc pas.
Vous pouvez cependant ne pas utiliser l'interface SFC et simplement la déclarer vous-même.
interface Prop<V> {
num: V;
}
// normal function
function Abc<T extends string | number>(props: Prop<T>): React.ReactElement<Prop<T>> {
return <div />;
}
// const lambda function
const Abc: <T extends string | number>(p: Prop<T>) => React.ReactElement<Prop<T>> = (props) => {
return <div />
};
export default function App() {
return (
<React.Fragment>
<Abc<number> num={1} />
<Abc<string> num="abc" />
<Abc<string> num={1} /> // string expected but was number
</React.Fragment>
);
}
Modèle d'usine:
import React, { SFC } from 'react';
export interface GridProps<T = unknown> {
data: T[];
renderItem: (props: { item: T }) => React.ReactChild;
}
export const GridFactory = <T extends any>(): SFC<GridProps<T>> => () => {
return (
<div>
...
</div>
);
};
const Grid = GridFactory<string>();
Il existe un modèle pour atténuer ce problème en déclarant un alias de type de composant générique en dehors de composant, puis en l'affirmant simplement lorsque vous en avez besoin.
Pas aussi joli, mais toujours réutilisable et strict.
interface IMyComponentProps<T> {
name: string
type: T
}
// instead of inline with component assignment
type MyComponentI<T = any> = React.FC<IMyComponentProps<T>>
const MyComponent: MyComponentI = props => <p {...props}>Hello</p>
const TypedComponent = MyComponent as MyComponentI<number>
Tu as ceci:
interface Prop<V> {
num: V;
}
Et vous avez défini votre composant comme ceci:
const myCom: SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
Cela ne fonctionnerait pas car vous auriez besoin de fournir un type concret pour la variable V
dans l'interface puisque vous l'implémentez dans votre composant.
Cela ressemble à quelque chose comme ça:
const myCom: SFC<Prop<object>> = <T>(props: Prop<T>)=> <div>test</div>
Notez mon utilisation de object
où vous aviez T
. C'est juste un exemple.