这里发生了一些事情。第一的:
TypeScript 没有太多的余地区别 https://github.com/microsoft/TypeScript/issues/13195属性/函数参数之间missing以及那些现在但是undefined
。 “可选性”注释foo?: Bar
代表两种情况。和,Partial<Test>
求值为具有两个可选属性的类型,相当于{one?: boolean, two?: boolean}
.
因此我可以称之为:
getPropOrFalse({ one: undefined }, "one"); // oops
这就是编译器现在的方式(直到并且除非微软/TypeScript#13195 https://github.com/microsoft/TypeScript/issues/13195以某种方式得到解决)。我可以想象跳过很多圈子来制作呼叫签名getPropOrFalse()
不允许someTest
带有“present-but-”的参数undefined
属性,但编译器可能仍然无法理解其实现中的含义getPropOrFalse()
,所以你必须使用断言之类的。我想说,不与类型系统作斗争并允许存在但-更健康undefined
特性。
The in
运算符检查属性是否存在,但不检查属性的值是否为undefined
或不。因此in
运算符不足以检查可选属性,而typeof foo.prop === "undefined"
实际上检查该属性是否是undefined
或不。 (是的,我知道,但您的情况并非如此;请继续阅读!)这种差异可以通过以下方式证明:
function getOneOrFalse(someOne: { one?: boolean }): boolean {
if ("one" in someOne) {
return someOne.one; // error! boolean | undefined
}
if (typeof someOne.one !== "undefined") {
return someOne.one; // okay
}
return false;
}
但是,显然,改变为typeof someTest[prop] === "undefined"
不适合你的getPropOrFalse()
功能:
function badGetPropOrFalse(someTest: Partial<Test>, prop: keyof Test): boolean {
if (typeof someTest[prop] !== "undefined") {
return someTest[prop]; // still error! boolean | undefined
}
return false;
}
是什么赋予了?这是第二件事:
问题与尝试输入防护有关indexed当属性不是单一属性时的属性访问(带括号)literal https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types。就你而言,自从prop
是一个变量,并且是联合类型"one" | "two"
,编译器无法(或不愿意)执行控制流分析缩小(请参阅 microsoft/TypeScript#10530 https://github.com/microsoft/TypeScript/issues/10530)。我猜有一个attempt https://github.com/microsoft/TypeScript/pull/10565来解决这个问题,但它对性能产生了重大影响,因此它似乎已被放弃(或至少被推迟)。我预计性能会受到一些影响,因为为了使其工作,编译器必须特定跟踪“变量”的类型someTest
当由变量索引时prop
”,这不能轻易地转化为缩小类型someTest
。 (毕竟,如果我有两个属性,prop1
and prop2
两种类型keyof Test
,我检查了someTest[prop1]
,它对类型没有影响someTest[prop2]
,尽管事实上prop1
and prop2
根据类型系统,它们是相同的类型。)
处理这个问题的方法是减轻编译器跟踪变量索引的负担,并将其分配给新的变量const
首先是变量,正如另一个答案中提到的:
function getPropOrFalse(someTest: Partial<Test>, prop: keyof Test): boolean {
const val = someTest[prop]; // boolean | undefined
if (typeof val !== "undefined") {
return val; // okay
}
return false;
}
当然,一旦我们开始像这样重构,我们就可以一路走下去:
function simplestGetPropOrFalse(someTest: Partial<Test>, prop: keyof Test): boolean {
return someTest[prop] ?? false;
}
(它使用新添加的无效合并 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing操作员)
好的,希望这有助于解释发生了什么。祝你好运!
链接到代码 https://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgCoQM5mQbwFDKHID2IEAXMgEbHEA2EcIA3AUWAO7GU32Mt4AvnjwBzCGAAKUYgAcA8lABicOhggAKHCTKUAriAAmEGKAiHkggDTIARKQi2AlKzwwDCMMFLU4hgOIS0nKKKmqaGMQAthDoWJSScFBeqgA8cWAAfDayMrKUANYQAJ7EMGiYYE48tAxMuGyEwOUauXLIoMiRMRlODUQDyFASelAgXdGxlQDabbIAuszIAPTLyNAyUACE1LX8yAA+yAbGpmSGjZaXzcgaYMWyEGUTPTNz88hbALxfdicmZkMzn6g0IwzAo3G3SmWFmeUWKzWWGAdDo6ygmx2vDq4yO-zO5kuwgG4MhyHg4VYwjcHi8PnEYHkZFCqnUGmhTIouB0EAA-DU+PVBNVdoLxvgBjcNPYyLYOlDJpy+hLQUMRmMXhBOQA6BxLVbozGEbH7PFGAHnVXIInXFr3R7PDlkXVkT4-P7mglA5WXEnqhUxHV6xEkApwYo2v0QjUU9RUkQ0kCebzjBnBBTKVkRSYZBJJFJ0dKVbLIOaFErPXoCnEgwgIUhYZAAN1UyF+0IycLkCINJvqZtOgNtt3tT3KLbR31+tnxgOBKtBpI1E-1a2IYYjA2JRCX41jEHjieTPgwwCisgYWECUjyLPC7JzlTzyWAaQyJbLyCKpXKVdFNYXNVowDGEwC7BZkF5XlySzQ8gA