我有一个对象,可以有两种类型。对象的类型取决于属性type
。type
可以是任何字符串,但如果type === "specific string"
则对象类型将不同,如下所示:
interface Input {
type: string;
value: any;
}
interface Checkbox {
type: "checkbox";
checked: boolean;
}
type EventUnion = Checkbox | Input;
但是当我尝试这样做时:
function handleEvent(event: EventUnion) {
if (event.type === "checkbox") {
console.log(event.checked); // Property 'checked' does not exist
}
};
有没有办法解决这个问题?
问题是根据Input
接口,type
属性很可能是"checkbox"
。 TypeScript 没有否定类型(无论如何从 TS3.5 开始(,因此无法指定类似string & not "checkbox"
的内容。
因此,如果event.type === "checkbox"
,您仍然无法确定event
是CheckBox
而不是Input
。 TypeScript 甚至不理解反向检查,event.type !== "checkbox"
暗示event
是一个Input
。 TypeScript 实际上只在检查可区分联合的判别属性时对联合类型进行基于控制流的收缩。判别属性必须是单值类型,因此检查类型string
的属性不会充当类型保护。
解决这个问题的一种方法是改变你对工会成员的歧视方式。 例如,检查是否存在已知仅存在于工会成员之一上的属性。 这种类型的检查从 TypeScript 2.7 开始就得到了支持:
function handleEvent(event: EventUnion) {
if ("checked" in event) {
console.log(event.checked); // okay
} else {
console.log(event.value); // okay
}
}
"checked"
的存在将event
缩小到CheckBox
,而不存在event
缩小到Input
。 这当然意味着您甚至不需要type
属性来区分CheckBox
和Input
.
如果要继续检查type
属性,可以通过创建自己的类型保护函数来传达此检查应该是类型保护:
function eventIsCheckBox(event: EventUnion): event is Checkbox {
return event.type === "checkbox";
}
eventIsCheckbox(event)
的返回类型是event is Checkbox
,一个类型谓词,它告诉编译器true
结果意味着event
是一个Checkbox
,而false
结果意味着event
不是Checkbox
。 这并不直接来自Input
和Checkbox
接口的定义;相反,此函数是向编译器断言此类检查有效的方式。 让我们使用它:
function handleEvent2(event: EventUnion) {
if (eventIsCheckBox(event)) {
console.log(event.checked); // okay
} else {
console.log(event.value); // okay
}
}
在运行时进行与原始代码相同的检查,但现在编译器将接受它确定event
是否为CheckBox
。
好的,希望有帮助;祝你好运!
链接到代码