如何在具有可以是特定单词或任何给定字符串的属性的类型联合上正确键入

  • 本文关键字:类型 字符串 属性 任何 单词 typescript
  • 更新时间 :
  • 英文 :


我有一个对象,可以有两种类型。对象的类型取决于属性typetype可以是任何字符串,但如果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",您仍然无法确定eventCheckBox而不是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属性来区分CheckBoxInput.


如果要继续检查type属性,可以通过创建自己的类型保护函数来传达此检查应该是类型保护:

function eventIsCheckBox(event: EventUnion): event is Checkbox {
return event.type === "checkbox";
}

eventIsCheckbox(event)的返回类型是event is Checkbox,一个类型谓词,它告诉编译器true结果意味着event是一个Checkbox,而false结果意味着event不是Checkbox。 这并不直接来自InputCheckbox接口的定义;相反,此函数是向编译器断言此类检查有效的方式。 让我们使用它:

function handleEvent2(event: EventUnion) {
if (eventIsCheckBox(event)) {
console.log(event.checked); // okay
} else {
console.log(event.value); // okay
}
}

在运行时进行与原始代码相同的检查,但现在编译器将接受它确定event是否为CheckBox


好的,希望有帮助;祝你好运!

链接到代码

相关内容

最新更新