我不知道如何将道具的类型链接在一起
interface MyExample {
id: number;
name: string;
}
export interface ListItemProps<ItemType> {
value: keyof ItemType;
formatter?: <K extends keyof ItemType>(value: ItemType[K]) => ItemType[K];
}
const ListItem = <T extends {}>(props: ListItemProps<T>) => null;
export default ListItem;
所以当我这样做
<ListItem<MyExample> value="name" formatter={(val: string) => val.toUpperCase()} />
<ListItem<MyExample> value="id" formatter={(val: number) => String(id)} />
它不应该警告我有关格式化程序的信息。
实际上我得到了:
答案 0 :(得分:1)
问题是,您需要一个额外的类型参数来保留表示要使用的密钥的实际类型。
interface MyExample {
id: number;
name: string;
}
export interface ListItemProps<ItemType, K extends keyof ItemType> {
value: K;
formatter?: (value: ItemType[K]) => string;
}
const ListItem = <T extends {}, K extends keyof T>(props: ListItemProps<T, K>) => null;
let s = <ListItem<MyExample, "name"> value="name" formatter={(val) => val.toUpperCase()} />
let s2 = <ListItem<MyExample, "id"> value="id" formatter={(val) => val.toFixed(4)} />
理想情况下,value
可以从用法中推断出来,但是TS不支持部分类型推断,所以这是我们能做的最好的工作(希望soon可以实现,但该功能看起来像JSX标记至少是一开始)
如果我们不介意使用HOC,还可以编写:
interface MyExample {
id: number;
name: string;
}
export interface ListItemProps<ItemType, K extends keyof ItemType> {
value: K;
formatter?: (value: ItemType[K]) => string;
}
const ListItem = <T extends {}>() => <K extends keyof T>(props: ListItemProps<T, K>) => null;
const MyExampleListItem = ListItem<MyExample>();
const s = <MyExampleListItem value="name" formatter={(val) => val.toUpperCase()} />;
const s2 = <MyExampleListItem value="id" formatter={(val) => val.toFixed(4)} />;
答案 1 :(得分:0)
(value: ItemType[K]) => ItemType[K]
定义输入和返回值必须相同。
因此formatter={(val: MyExample['name']) => 'coucou'}
无效,因为输入(MyExample [string])和return(string)不同。
所以我认为您应该将(value: ItemType[K]) => ItemType[K]
更改为(value: ItemType[K]) => ItemType[K] | string