Typescript:如何为联合类型中的枚举添加类型保护?

4
以下代码出现了错误:
  1. 'instanceof' 表达式的左侧必须是 'any' 类型、对象或类型参数。
  2. 类型 'E | C' 不能赋值给类型 'E'。类型 'C' 不能赋值给类型 'E'。

请注意,保留了 HTML 标签。
    enum E { FIRST = 1, SECOND = 2 }; 

    class C {
        value: E;    

        constructor(arg: C | E) {
            if (arg instanceof C) { // 1.
                this.value = arg.value;
            } else {
               this.value = arg; // 2.
            }
        }
    }

    var a: C = new C(E.SECOND);
    console.log('a.value = ' + a.value);

    var b: C = new C(a);
    console.log('b.value = ' + b.value);

尽管存在错误,但代码似乎在TypeScript Playground 上编译正常并达到预期效果。

PS:一个简单的解决方法是用类型“any”替换联合类型,尽管这会违背TypeScript的理念。 - Grathau
2个回答

6

有两个问题。

编译器中存在一个bug,当联合类型的其中一个成员不是对象类型时,不允许使用instanceof。这个问题正在修复中(https://github.com/Microsoft/TypeScript/issues/2775)。

另一个问题是,在else块中,instanceof不会导致类型缩小(https://github.com/Microsoft/TypeScript/issues/1719),因为失败的instanceof检查并不一定意味着对象不符合指定的接口。目前这种行为是“设计上的”,但我鼓励您留下评论,说明您认为这种行为令人惊讶或不理想(我确实这么认为)。


3

Ryan当然既雄辩又准确,但我可以为您提供一个临时解决方案,您可能会发现它有用。尽管它可能有用,但请不要将其作为答案接受,因为长期来看,解决与类型保护相关的问题会更好。

class C {
    value: E;    

    constructor(arg: C | number) {
        if(typeof arg === 'number') {
            this.value = arg;
        } else {
            this.value = arg.value;
        }
    }
}

这个不太好的解决方案依赖于枚举和数字之间的良好兼容性。您还可以从 typeof 检查缩小 else 语句的副作用中获益。

我会采用这个修复方案,因为枚举/数字参数更加常见,所以测试它应该先于其他类型进行。 - Grathau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接