我正在尝试键入以下组件:
type Props<Data> = {
data: Data[]
render: ({ value }: { value: Data }) => React.ReactElement
}
const List: React.FC<Props> = ({data, render}) => {…}
我遇到的问题是,我希望Data
是通用的,无论您在数组中传入什么内容,我都想强烈键入渲染以使value
知道为Data
类型。问题是我不确定如何使用它。理想情况下,我想执行以下操作:
<List data={[1,2,3]} render={(value) => <div>{value + 2}</div>}/>
并完成操作,在这种情况下render将知道value
是一个数字。这可能吗?
答案 0 :(得分:0)
如果您尝试传递数字数组(从data={1,2,3}
推算得出)。那么您只需要将数字作为通用类型传递给您的Props
。您需要做更多的映射才能使类型正确匹配。
export interface ListProps<T = unknown> {
data: T[];
render: (item: T) => React.ReactElement;
}
export const GenericListItems = <T extends any>(): React.FC<ListProps<T>> => ({
data,
render
}): any => {
return data.map(render);
};
严格输入您的列表的样子
const StringList = GenericListItems<string>();
const NumberList = GenericListItems<number>();
interface JsxClass<P, S> extends React.Component<P, S> {
render(): React.ReactElement<P>[];
}
interface GenericComponentType<P, S> {
new (props: P): JsxClass<P, S>;
}
interface ListProps<T> {
data: T[];
render: (value: T) => any;
}
class List<T> extends React.Component<ListProps<T>, {}> {
render(): React.ReactElement<any>[] {
return this.props.data.map(this.props.render);
}
}
严格输入您的列表的样子
const NumberList: GenericComponentType<ListProps<number>, {}> = List;
const StringList: GenericComponentType<ListProps<string>, {}> = List;
这两个(组件类或功能组件)实例都可以以相同的方式使用。
<NumberList
data={[1, 2, 3]}
render={value => <div>{value + 2}</div>}
/>
<StringList
data={["I", "Render", "Strings"]}
render={value => <div>{value}</div>}
/>
答案 1 :(得分:0)
如果您需要Data
作为通用参数,则可以在组件定义中声明它。
所以像class List<Data> extends React.Component<ListProps<Data>>
或function List<Data>(props: ListProps<Data>)
之类的东西,让打字稿完成其余的工作。
这是一个完整的代码示例:
import React from "react";
interface ListProps<Data> {
data: Data[];
render: (item: Data) => React.ReactNode;
}
function List<Data>({ data, render }: ListProps<Data>) {
return <div>{data.map(render)}</div>;
}
const element1 = <List data={[1.234, 2.345, 3.456]} render={v => <span>{v.toFixed(2)}</span>} />;
const element2 = (
<List data={["abc", "bca", "cab"]} render={v => <span>{v.substring(0, 1)}</span>} />
);
编辑
要强制数据为特定类型,可以将通用参数传递给List,如下所示:
const element1 = (
<List<number>
// Typescript will complain:
// Type 'string' is not assignable to type 'number'.ts(2322)
data={["1.234", 2.345, 3.456]}
render={v => <span>{v.toFixed(2)}</span>}
/>
);
在最后一个示例中,如果删除通用参数,则会收到另一个错误,因为数据将被推断为number | string
:
const element1 = (
<List
data={["1.234", 2.345, 3.456]}
// Typescript will complain:
//Property 'toFixed' does not exist on type 'ReactText'.
// Property 'toFixed' does not exist on type 'string'.ts(2339)
// and `v` is infered to be (parameter) v: string | number
render={v => <span>{v.toFixed(2)}</span>}
/>
);