Bra*_*ven 5 javascript typescript
这是错误的示例:
interface Block {
id: string;
}
interface TitleBlock extends Block {
data: {
text: "hi",
icon: "hi-icon"
}
}
interface SubtitleBlock extends Block {
data: {
text: "goodbye",
}
}
interface CommentBlock extends Block {
author: string;
}
type BlockTypes = TitleBlock | SubtitleBlock | CommentBlock
function mapper(block : BlockTypes) {
if(block?.data?.text){ // TS Error here!!!
/** do something */
}
}
Run Code Online (Sandbox Code Playgroud)
当块具有特定属性时,我想在函数中执行某些操作,但 TS 不允许我这样做,即使 BlockType 中存在具有该属性的类型。
管理此类功能的最佳方法是什么?
可选的链接运算符 (?. )仅防止null和undefined;它不会将联合类型表达式过滤为已知包含该键的成员。请参阅Microsoft/TypeScript#33736 中的此评论以获得规范答案。
问题在于 TypeScript 中的对象类型是开放的,并且允许包含比编译器所知更多的属性。因此,如果block.data为真,不幸的是并不意味着block.data.text存在:
const oof = {\n id: "x",\n author: "weirdo",\n data: 123\n}\nmapper(oof); // accepted\nRun Code Online (Sandbox Code Playgroud)\n这oof是一个有效的CommentBlock,所以mapper(oof)是允许的,并且oof.data是真实的,但是oof.data.text是undefined,如果你尝试将它视为 ,你将会遇到问题string。
因此,允许可选链接按照您想要的方式过滤联合是不健全的(即类型不安全)。
\n如果您认为不太oof可能出现类似情况,这里的解决方法是使用运算in符作为类型保护:
function mapper(block: BlockTypes) {\n if ("data" in block) {\n block.data.text.toUpperCase()\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n这工作正常,没有编译器错误。当然,它仍然不健全,与缩小范围完全相同?.......如果您调用,则mapper(oof)不会出现编译器错误,但您会收到运行时错误。所以你应该小心。
inTypeScript 允许以这种方式运行,但不允许其他类似的构造,这有点奇怪。您可以阅读microsoft/TypeScript#10485中的讨论来了解为什么会发生这种情况。大多数情况下,人们在写作时"foo" in bar很少会做错事,但其他结构(如)bar.foo && bar.foo.baz被误用的情况更频繁。但这是 TS 团队的观点,而不是我的观点。\xe2\x80\x8d\xe2\x99\x82\xef\xb8\x8f
| 归档时间: |
|
| 查看次数: |
736 次 |
| 最近记录: |