尝试使 keyof T
成为字符串返回类型,并且在尝试将属性传递到 tags
时似乎可以工作。虽然当将它用作索引时,它似乎并没有缩小它将成为一个字符串的范围。
错误:Type 'T[KeyOfType<T, string>]' is not assignable to type 'string'.
我做错了什么还是打字稿限制?
type KeyOfType<T, U> = { [P in keyof T]: T[P] extends U ? P : never }[keyof T];
interface TagProps<T> {
tags: T[];
tagLabelKey: KeyOfType<T, string>;
}
const tag = [{
id: 1,
name: 'raw',
}]
const tags = <T,>({tags, tagLabelKey}: TagProps<T>) => {
const getLabel = (tag: T): string => {
return tag[tagLabelKey];
}
}
tags({ tags: tag, tagLabelKey: 'name' })
答案 0 :(得分:1)
这确实似乎是一个打字稿限制。来自 this github issue 上的一位打字稿开发人员:
<块引用>这里的问题是我们没有更高阶的推理来说明“如果一个键来自过滤掉不是字符串的键的操作,那么通过该键进行索引一定会产生一个字符串”。从 TS 的角度来看,FilterProperties 类型在逻辑上实际上是不透明的。
他甚至提出了一种实现相同语义的替代方法。转换为您的情况(并假设您想在数组上映射 getLabel
并返回结果):
interface TagProps<P extends string> {
tags: Record<P, string>[];
tagLabelKey: P;
}
const tags = <P extends string,>({tags, tagLabelKey}: TagProps<P>) => {
const getLabel = (tag: Record<P, string>): string => {
return tag[tagLabelKey];
}
return tags.map(getLabel)
}
const tag = [{
id: 1,
name: 'raw',
}]
tags({ tags: tag, tagLabelKey: 'name' }) // typechecks
tags({ tags: tag, tagLabelKey: 'id' }) // does not typecheck
高级区别在于不是在标签对象类型中通用和提取字符串键(通过KeyOfType
),在键中通用 strong> 并使用它构建标签对象的相关部分,同时只允许将字符串分配给它(通过 Record<P, string>
)。
或者使用更少的显式类型和更多的类型推断:
interface TagProps<P extends string> {
tags: Record<P, string>[];
tagLabelKey: P;
}
const tags = <P extends string,>({tags, tagLabelKey}: TagProps<P>): string[] => {
return tags.map((tag) => tag[tagLabelKey])
}