Тип общего безголового компонента? ИЛИ Расширение универсального интерфейса функции в машинописном тексте, чтобы иметь более общий характер?
Проблема: интерфейс Stateless Functional Component
задан как
interface SFC<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
propTypes?: ValidationMap<P>;
}
Тип реквизита моего компонента также является общим:
interface Prop<V>{
num: V;
}
Как правильно определить мой компонент? как:
const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
выдает ошибку в character 27
которая Cannot find name 'T'
Вот: {
(props: Readonly
context?: any): number;
displayName?: string;
defaultProps?: Partial
;
}
interface Prop{
num: V;
}
const Search: FunctionalComponent >= (props) => {
return 10;
}
rel=noreferrer>Typescript Детская площадка модифицированного примера
MyFindings:
1: Typescript 2.9.1 поддерживает общий компонент Stateful: 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: Расширение SFC
для создания нового интерфейса, как упомянуто в следующем ответе, сделало бы тип prop компонента как any
: Typescript Реагирует на функцию без сохранения состояния с общими типами параметров/возвращаемых значений, которые мне не нужны. Я хочу дать правильный тип для моей опоры
Ответы
Ответ 1
Вы не можете использовать дженерики, как это:
const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
Спецификация TypeScript гласит:
Конструкция формы
< T > ( ... ) => { ... }
может быть проанализирован как выражение функции стрелки с параметром типа или утверждением типа, примененным к функции стрелки без параметра типа.
источник; Microsoft/TypeScript spec.md
Ваше объявление не соответствует шаблону, определенному в спецификации TypeScript, поэтому оно не будет работать.
Однако вы не можете использовать интерфейс SFC и просто объявить его самостоятельно.
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>
);
}
Ответ 2
Существует шаблон, позволяющий смягчить эту проблему, объявляя псевдоним универсального типа компонента вне компонента, а затем просто утверждая его, когда это необходимо.
Не так красиво, но все же многократно и строго.
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>
Ответ 3
Заводская модель:
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>();
Ответ 4
У вас есть следующее:
interface Prop<V> {
num: V;
}
И у вас есть свой компонент, определенный следующим образом:
const myCom: SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
Это не сработает, так как вам нужно будет указать конкретный тип для V
в интерфейсе, так как вы реализуете его в своем компоненте.
Это выглядит примерно так:
const myCom: SFC<Prop<object>> = <T>(props: Prop<T>)=> <div>test</div>
Обратите внимание на мое использование object
где у вас есть T
Это просто пример.
Ответ 5
Вы можете отказаться от аннотирования с помощью React.FC
и просто написать:
const myCom = <T>(props: Prop<T>) => <div>test</div>
Ответ 6
Я предлагаю подобное, хотя и немного другое решение (мозговой штурм с другом). Мы пытались создать оболочку Formik, и нам удалось заставить ее работать следующим образом:
import React, { memo } from 'react';
export type FormDefaultProps<T> = {
initialValues: T;
onSubmit<T>(values: T, actions: FormikActions<T>): void;
validationSchema?: object;
};
// We extract React.PropsWithChildren from React.FunctionComponent or React.FC
function component<T>(props: React.PropsWithChildren<FormDefaultProps<T>>) {
// Do whatever you want with the props.
return(<div>{props.children}</div>
}
// the casting here is key. You can use as typeof component to
// create the typing automatically with the generic included..
export const FormDefault = memo(component) as typeof component;
И затем, вы используете это как:
<FormDefault<PlanningCreateValues>
onSubmit={handleSubmit}
initialValues={PlanningCreateDefaultValues}
>
{/*Or any other child content in here */}
{pages[page]}
</FormDefault>
Я не смог достичь этого с помощью выражений методов:
const a: React.FC<MyProp> = (prop) => (<>MyComponent</>);