Javascript 通用无状态组件反应的类型?或在打字稿中扩展通用功能接口以获得进一步的通用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/51459971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Type of Generic Stateless Component React? OR Extending generic function interface in typescript to have a further generic?
提问by Naman Kheterpal
Problem: The interface of Stateless Functional Componentis given as
问题: 的接口Stateless Functional Component给出为
interface SFC<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
propTypes?: ValidationMap<P>;
}
The prop type of my component is also generic as:
我的组件的 prop 类型也是通用的:
interface Prop<V>{
num: V;
}
How to properly define my component? as:
如何正确定义我的组件?作为:
const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
gives an error at character 27that Cannot find name 'T'
在给出了一个错误character 27的是Cannot find name 'T'
Here is :Typescript Playground of modified example
这是:修改示例的 Typescript Playground
MyFindings:
我的发现:
1:Typescript 2.9.1 support Stateful Generic Component: http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#generic-type-arguments-in-jsx-elements
1:Typescript 2.9.1 支持有状态的通用组件: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: Extending SFCto make a new interface as mentioned in following answer would make component's prop type as any:
Typescript React stateless function with generic parameter/return typeswhich I don't want. I want to give proper type for my prop
2:扩展SFC以创建以下答案中提到的新接口将使组件的道具类型为any:
Typescript React stateless function with generic parameter/return types thatI don't want. 我想为我的道具提供正确的类型
回答by jmattheis
You can't use generics like this:
你不能像这样使用泛型:
const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
The TypeScript spec states:
TypeScript 规范指出:
A construct of the form
< T > ( ... ) => { ... }could be parsed as an arrow function expression with a type parameter or a type assertion applied to an arrow function with no type parameter.
形式的构造
< T > ( ... ) => { ... }可以解析为带有类型参数的箭头函数表达式或应用于没有类型参数的箭头函数的类型断言。
source; Microsoft/TypeScript spec.md
Your declaration doesn't match the pattern defined in the TypeScript spec, therefore it wont work.
您的声明与 TypeScript 规范中定义的模式不匹配,因此它不起作用。
You can however don't use the SFC interface and just declare it yourself.
但是,您可以不使用 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>
);
}
回答by vadistic
There's a pattern to mitigate this issue by declaring generic component type alias outside of component and then simply asserting it when you need it.
有一种模式可以通过在组件外部声明通用组件类型别名,然后在需要时简单地断言它来缓解此问题。
Not as pretty, but still reusable and 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>
回答by chris
Factory pattern:
工厂模式:
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>();
回答by Jose A
I'm proposing a similar yet albeit slightly different solution (brainstormed with a friend). We were trying to create a Formik wrapper, and managed to get it working in the following fashion:
我提出了一个类似但略有不同的解决方案(与朋友集思广益)。我们试图创建一个 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;
And then, you use it like:
然后,您可以像这样使用它:
<FormDefault<PlanningCreateValues>
onSubmit={handleSubmit}
initialValues={PlanningCreateDefaultValues}
>
{/*Or any other child content in here */}
{pages[page]}
</FormDefault>
I haven't been able to achieve this with method expressions:
我无法通过方法表达式实现这一点:
const a: React.FC<MyProp> = (prop) => (<>MyComponent</>);
const a: React.FC<MyProp> = (prop) => (<>MyComponent</>);
回答by serdarsen
An example of generic stateless component according to jmattheis's post.
根据 jmattheis 的帖子的通用无状态组件示例。
MyGenericStatelessComponent.tsx
MyGenericStatelessComponent.tsx
import React from "react";
type Prop<T> = {
example: T;
};
const MyGenericStatelessComponent: <T extends Record<string, number | string>>(props: Prop<T>) => JSX.Element = <
T extends Record<string, unknown>
>(
props: Prop<T>
): JSX.Element => {
return (
<div>
Example Prop id: {props.example.id}, Example Prop name: {props.example.name}
</div>
);
};
export default MyGenericStatelessComponent;
Usage:
用法:
<MyGenericStatelessComponent example={{ id: 1, name: "test01" }} />
回答by codejockie
You have this:
你有这个:
interface Prop<V> {
num: V;
}
And you have your component defined like this:
你的组件定义如下:
const myCom: SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
That wouldn't work as you'd need to supply a concrete type for the Vin the interface since you're implementing it in your component.
这不起作用,因为您需要V在接口中为 提供具体类型,因为您正在组件中实现它。
That look something like this:
看起来像这样:
const myCom: SFC<Prop<object>> = <T>(props: Prop<T>)=> <div>test</div>
Note my use of objectwhere you had T. This is just an example.
请注意我对object你所拥有的地方的使用T。这只是一个例子。
回答by Nikola Mihajlovi?
You can give up on annotating with React.FCand simply write:
您可以放弃注释React.FC并简单地编写:
const myCom = <T>(props: Prop<T>) => <div>test</div>

