Fut*_*ake 5 generics types typescript
我有以下类和接口定义:
import { Component } from 'react';
type KeysMatching<T, V> = {
[K in keyof T]-?: T[K] extends V ? K : never
}[keyof T];
interface SearchListProps<T extends object, K extends KeysMatching<T, string>> {
data: T[];
sort_and_filter_key: K;
}
class SearchList<ItemDataT extends object, K extends KeysMatching<ItemDataT, string>> extends Component<SearchListProps<ItemDataT, K>> {
constructor(props: SearchListProps<ItemDataT, K>) {
super(props);
const value = props.data[0][props.sort_and_filter_key]; // ItemDataT[K] -> should be string
}
}
// exmple case:
interface DataExample {
name: string,
city: string,
id: number,
content: object
// etc
}
const example_data: DataExample[] = [
{
name: "asd",
city: "bcn",
id: 1,
content: {}
},
{
name: "dkg",
city: "nld",
id: 2,
content: {}
}
];
<SearchList data={example_data} sort_and_filter_key={"city"}></SearchList>
Run Code Online (Sandbox Code Playgroud)
正如您在代码中所注释的那样,打字稿认为 value 是类型,ItemDataT[K]但它应该是string。
为什么?因为该属性sort_and_filter_key应该只允许其值为字符串的键,因为以下通用表达式:K extends KeysMatching<T, string>。但打字稿似乎不明白这一点。
自动完成似乎确实可以理解,请参见下图:

由于这张图clear只允许保证是字符串的两个key。
我如何让 tsc 也理解这一点?
如果有任何不清楚的地方,请告诉我,以便我修改问题。
问题似乎是Typescript 推理能力对于泛型类型的限制 - Typescript 不会跟踪所有可推理的约束。这样做肯定需要一些权衡。
对于具体类型,推理按预期进行:
const props: SearchListProps<DataExample> = {
data: example_data,
sort_and_filter_key: 'city',
};
const ok_string = props.data[0][props.sort_and_filter_key];
Run Code Online (Sandbox Code Playgroud)
如果是泛型类型,我们需要手动向 TS 引擎给出我们到底感兴趣的提示:
interface SearchListProps<T> {
data: (T & Record<KeysMatching<T, string>, string>)[];
sort_and_filter_key: KeysMatching<T, string>;
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,我们可以T与其他任何东西相交 - 例如Record<KeysMatching<T, string>, number>,但是我们无法SearchListProps使用具体类型进行初始化。
固定和简化版本: https://stackblitz.com/edit/react-ts-x4jdez
顺便提一句。props.data[0][props.sort_and_filter_key]不安全(noUncheckedIndexedAccess ]。
| 归档时间: |
|
| 查看次数: |
281 次 |
| 最近记录: |