Problema : la interfaz del Stateless Functional Component se da como
interface SFC<P = {}> { (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null; propTypes?: ValidationMap<P>; }El tipo de accesorio de mi componente también es genérico como:
interface Prop<V>{ num: V; }¿Cómo definir correctamente mi componente? como:
const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div> da un error en el character 27 que Cannot find name 'T'
Aquí está: Typescript Playground de ejemplo modificado
Mis Hallazgos :
1: Typescript 2.9.1 admite componente genérico con estado: 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: Extender SFC para crear una nueva interfaz como se menciona en la siguiente respuesta haría que el tipo de accesorio del componente sea any : Typescript React función sin estado con parámetros genéricos/tipos de retorno que no quiero. Quiero dar el tipo adecuado para mi accesorio.
No puedes usar genéricos como este:
const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>La especificación de TypeScript establece:
Una construcción de la forma
< T > ( ... ) => { ... }podría analizarse como una expresión de función de flecha con un parámetro de tipo o una aserción de tipo aplicada a una función de flecha sin parámetro de tipo.
fuente; Microsoft/Especificación de TypeScript.md
Su declaración no coincide con el patrón definido en la especificación de TypeScript, por lo tanto, no funcionará.
Sin embargo, no puede usar la interfaz SFC y simplemente declararla usted mismo.
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> ); }Hay un patrón para mitigar este problema al declarar el alias de tipo de componente genérico fuera del componente y luego simplemente afirmarlo cuando lo necesite.
No tan bonito, pero sigue siendo reutilizable y estricto.
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>Patrón de fábrica:
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>();Para evitar errores de reglas de ganchos, debe perfeccionar la sintaxis de esta manera:
import React, { FC } from 'react'; export interface GridProps<T = unknown> { data: T[] renderItem: (props: { item: T }) => React.ReactChild } export const GridFactory = <T extends any>() => { const Instance: FC<GridProps<T>> = (props) => { const [state, setState] = useState(props.data) return <div>...</div> } return Instance } const Grid = GridFactory<string>()