繁体   English   中英

打字稿中的联合类型推断

[英]union type inference in typescript

type p1 = { a: number, b: string }
type p3 = { a: string }
type p4 = p1 | p3

let demo: p4 = { a: '123', b: '123' }

function isP3(obj: p4): obj is p3 { 
    return typeof (<p3>obj).a === 'string'
}

function func(obj: p4) {
    if ('b' in obj) {
        // Uncaught TypeError: obj.a.toFixed is not a function
        obj.a.toFixed() //<- Now, no error is given
    } else { 

    }
}
func(demo)

为什么demo初始化时没有报错? 用户定义的类型保护

这是TypeScript 中的一个未解决的问题 (microsoft/TypeScript#20863) 您的联合类型不是可区分的联合,因此编译器在执行多余的属性检查之前不会将联合拆分为成员。 大多数人(包括我自己)都希望对工会的每个成员进行额外的财产检查,无论工会是否受到歧视。 不过,就目前而言,情况就是这样:编译器认为"b"是至少一个联合成员中可接受的属性,并决定不抱怨。

请注意,多余的属性检查是一种方便,而不是类型安全问题。 TypeScript 中的对象类型是open ,你总是可以在不违反类型的情况下向它们添加更多的属性而不是定义中的内容。 尽管具有y属性,但值{x: 1, y: 2}是有效的{x: number} 另一种说法是 TypeScript 中的对象类型并不精确 因此,技术上正确的是{ a: '123', b: '123' }是一个有效的p3 ,因此也是一个有效的p4 因此,从技术上讲,您不能仅通过检查b的存在与否来区分p1p3 是的,如果你只是想说const demo: p3 = {a: '123', b: '123'}你会在"b"上得到一个过多的属性警告,但这正如我所说,只是为了方便. 很容易被打败:

const demo1 = { a: '123', b: '123' };
const demo2: p3 = demo1; // no error

此时您可能想知道:“等等,如果"b"没有正确区分p1p3 ,为什么编译器认为它在func()内部?”。 好问题:

if ('b' in obj) { // why does the compiler think this narrows obj to p1?
    obj.a.toFixed() // no error, but blows up at runtime
}

好吧,事实证明in类型保护是故意不健全的 从技术上讲,使用它是不安全的,但人们会这样做,通常这不是问题。 但这对你没有帮助。 那好吧。


那么,你应该在这里做什么? 如果您的目的是测试b区分p1p3 ,那么您的p3类型应该清楚地表明:

type p3 = { a: string, b?: undefined }; // p3 cannot have a defined "b" property    

现在, 从 TypeScript 3.2+ 开始p4类型是一个真正的可区分联合。 所以这是一个错误:

let demo: p4 = { a: '123', b: '123' } // error now

并使不健全的'b'测试显示为错误。 如果你想做一个“好”的b测试,你现在可以测试obj.b !== undefined ,它肯定会用新的p3定义区分p1p3

function func(obj: p4) {
    if ('b' in obj) {
        obj.a.toFixed() // error now
    }

    if (obj.b !== undefined) {
        obj.a.toFixed(); // okay
    }
}

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

代码链接

使用您的自定义类型保护函数来缩小类型而不是'b' in obj'b' in obj

    if (!isP3(obj)) {
        obj.a.toFixed() // Error
    } else { 

    }
}

关于作业let demo: p4 = { a: '123', b: '123' }没有给出错误也让我感到困扰。 正如我发现的那样,如果我们将a定义为布尔值而不是数字,它将正常工作(这意味着给出错误)。 看起来只有当鉴别器类型包含联合类型本身时,分配才会失败。 您可以订阅此问题以获取详细信息https://github.com/microsoft/TypeScript/issues/35861

关于此事的规范部分并未完全解释当前的行为。 看起来必须要查看编译器本身才能进行解释。 https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#34-union-types

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM