属性'type'在类型'object'上不存在,即使经过`"type"in'的检查
回答 3
浏览 2098
2022-08-14
这段代码编译失败。
const nodeIsUseless = (node: unknown) =>
node !== null &&
typeof node === "object" &&
"type" in node &&
typeof node.type === "string" &&
node.type === "JSXText";
因为在最后两行中:
Property 'type' does not exist on type 'object'.(2339)
...这本身我可以理解,但我不明白为什么在"type" in node
检查之后,TS推断node
仍然是object
的类型,而不是{ type: unknown; [key: string]: unknown }
的类型,这就不会触发错误。
我想不出有什么办法可以在没有cast和运行时检查的情况下满足编译器对用户定义的类型保护,希望有比我更聪明的人看到这一点。我也意识到这并不是问题的关键所在,问题的关键在于推理。
- Jared Smith 2022-08-14
3 个回答
#1楼
得票数 4
不幸的是,TypeScript内置的in
操作符类型防护并不像你所期望的那样强大。
从一个裸露的object
,它将不推断出被测试的属性是可用的。它可以推断出它确实存在,只有如果它是已经潜在可用的,例如,在一个联合的类型中。也就是说,控制流不会使被测试的属性 "出现",而只是试图区分联合的类型。
declare const o: object;
if ("type" in o) {
o.type // Error: Property 'type' does not exist on type 'object'.
//^? object
}
declare const u: Number | String; // Note: using class only for the sake of the demo
if ("toFixed" in u) {
u.toFixed(); // Okay
//^? Number
}
在你的例子中,你可以为node
参数指定一个联合体,其可能的类型是{ type: unknown }
。
然而,unknown
顶级类型吸收了联合中的所有其他类型,所以它必须被其他所有类型所取代,例如使用特殊类型{}
来代表普通类型。
const nodeIsUseless = (node: undefined | null | {} | { type: unknown }) =>
node !== null &&
typeof node === "object" &&
// ^? {} | { type: unknown } | undefined
"type" in node &&
// ^? {} | { type: unknown }
typeof node.type === "string" && // Okay
// ^? { type: unknown }
node.type === "JSXText"; // Okay
#2楼
已采纳
得票数 4
虽然代码是正确的,但TypeScript不具备从"type" in node
推断出{ type: unknown }
的能力,但这个功能目前正在开发中。
2022-09-21更新:随着上述PR的合并,现在可以在typescript@next中完成,应该很快就能在typescript@latest中使用。
另请参见关于meta的讨论,关于这个答案。
#3楼
得票数 2
你应该这样做。
const nodeIsUseless = (node: unknown) =>
node !== null &&
node !== undefined &&
node instanceof Object &&
!Array.isArray(node) &&
"type" in node &&
typeof node["type"] === "string" &&
node["type"] === "JSXText";
只需要检查insonceof
而不是typeof
,并使用object["key"]
方法来访问值而不是.key
。 此外,确保项目不是数组是很好的做法,因为instonceof [] === 'object'
也是如此。
你是用什么版本的typescript做的?对我来说似乎并不适用。
- Nathan Chappell 2022-11-11