我正在尝试编写一些代码,对来自任意接口/类(作为通用参数提供)的一组字符串属性名称执行某些操作。
我的第一次尝试是这样的:
function doSomething<T extends object>(props: (keyof T)[]) {
for (let prop of props) {
const x: string = prop;
}
}
这会在以
const
: 开头的行中导致编译器错误
TS2322:键入“字符串|编号 | symbol' 不可分配给类型 'string'。
类型“数字”不能分配给类型“字符串”。
现在,第一行似乎很清楚了——
keyof T
可能是一个字符串,但也可能是一个数字,或者一个符号。
然而,第二行出乎我的意料——为什么编译器会假设
prop
是一个 number
而没有别的?或者它只是一个可能的、相互矛盾的案例的例子?
无论如何,我想我可以简单地限制我的循环体只处理那些字符串的属性名称:
function doSomething<T extends object>(props: (keyof T)[]) {
for (let prop of props) {
if (typeof prop === 'string') {
const x: string = prop;
}
}
}
但是现在,我的类型检查条件
typeof prop === 'string'
被突出显示,并显示一条消息:
无效的“typeof”检查:“prop”不能有“string”类型
为什么
prop
永远不会是一个字符串?当我用示例类调用我的函数时,我肯定可以传递一个字符串数组(显然,只要这些字符串与示例类的属性名称匹配)。
或者这些字符串是否以某种方式隐式转换为
symbol
?事实上,如果我将类型检查条件更改为 typeof prop === 'symbol'
,就不会再出现永远不会匹配的警告。但是,在第一个错误消息中,keyof T
被明确地说是字符串或数字或符号,那么在什么情况下 would 它根本就是一个字符串?
我的代码现在处于可以在 Jest 单元测试中运行的状态,并且 - 惊喜,惊喜 - 结果
prop
实际上 is 是一个字符串。它不能具有字符串类型的建议实际上是错误的。 (不幸的是,我无法关闭它,因为 WebStorm 不会泄露工具链中的哪个部分生成了消息。)
然而,第二行出乎我的意料——为什么编译器会假设 prop 是一个数字而不是别的?
这不是假设,它只是遍历了工会的所有可能性。 Typescript 考虑了
string
的情况,认为没有问题。然后它考虑它是 number
的情况,并且该情况会导致错误,因此它显示了这一点。 symbol
也会导致错误,但为了简洁起见,打字稿只显示它发现的第一个问题。
换句话说:第 2 行解释了 typescript 如何推断出第 1 行的错误
但是现在,我的类型检查条件 typeof prop === 'string' 被突出显示,并显示一条消息:
无效的“typeof”检查:“prop”不能有“string”类型
为什么 prop 永远不会是字符串?
这不是打字稿错误。例如,您不会在 this typescript playground 中看到它。这可能是一个 lint 错误。谷歌搜索让我找到了this question这可能是相关的。