此问题使用React代码,但特定于打字稿而不是react。
我正在使用一个简化的示例来尝试使它更易于阅读。我有一个组件MyList
,它带有一个传递给props类型的泛型类型参数。
此泛型类型推断一个用于生成子组件的对象。我想使用T[keyof T]
||的值来键控每个子组件。其在T[]
中的索引。
创建列表并使用索引没问题,但是我无法弄清楚如何正确键入listKey
以便它可以与期望key
的reacts number | string | undefined
属性一起使用
type MyListProps<T> = {
list: T[],
listKey: keyof T,
contentKey: keyof T
}
class MyList<T extends object> extends React.Component<MyListProps<T>, any> {
public render() {
return (
<div>
{ this.props.list.map((value: T, index: number) => {
const key = value[this.props.listKey];
return (
// Type T[keyof T] is not assignable
// to type 'number | string | undefined'
<Item key={key}>{value[this.props.contentKey]}</Item>
);
}
</div>
);
}
}
我如何推断出listKey
类型可以使用泛型分配给预期的反应key
道具类型?
答案 0 :(得分:1)
由于您要将索引访问的结果分配给key
,因此需要限制该索引操作可以返回的内容。一种方法是对T
使用约束:
class MyList2<T extends Record<string, string | number >> extends React.Component<MyListProps2<T>, any> {
public render() {
return (
<div>
{ this.props.list.map((value: T, index: number) => {
const key = value[this.props.listKey];
return (
<Item key={key}>{value[this.props.contentKey]}</Item>
);
})}
</div>
);
}
}
这确实有一个局限性,就是限制了您在T
中可能拥有的值,这可能是一个问题(或者不取决于您的用例)。
另一个更复杂的选择是限制使用listKey
返回的索引。这确实需要一个额外的类型参数,但它具有更大的灵活性:
type MyListProps<T, LK extends PropertyKey> = {
list: Array<T & Record<LK, string>>,
listKey: LK,
contentKey: keyof T
}
declare const Item: React.FC<{}>
class MyList<T, LK extends PropertyKey> extends React.Component<MyListProps<T, LK>, any> {
public render() {
return (
<div>
{this.props.list.map((value, index: number) => {
const key = value[this.props.listKey];
return (
<Item key={key}>{value[this.props.contentKey]}</Item>
);
})}
</div>
);
}
}
let x = <MyList listKey="a" contentKey="a" list={[
{ a: "", b: 0, p: {} }
]} ></MyList>
或者在这种情况下,您可以放弃类型安全,而只需使用类型断言。