与空对象的并集会导致类型擦除

时间:2019-03-06 21:52:14

标签: typescript

TypeScript Playground

interface Something {
    a: string;
}

interface Test {
    [key: string]: Something | undefined 

}
// Expecting: Something | {}
// Inferred: {}
const getSomething = (t: Test) => t['key'] || {}

// Usage:

declare const test: Test;

// Expecting: string | undefined
// Inferred: Error: `a` does not exist on type
const a = getSomething(test).a;

{}与对象的并集会删除对象的类型是什么原因?

如果我写:

type EmptyObject = { [key: string]: undefined }

并使用{} as EmptyObject代替,然后一切都会按预期进行。

1 个答案:

答案 0 :(得分:2)

通常,为了进行类型检查,将{}与任何非原始(对象)类型的并集减少为{}。这是因为在TypeScript中,{}作为类型实际上并不意味着“没有属性的对象”,而是意味着“没有已知属性的对象”,因此通常的类型兼容性规则可以{}可以用作最终超类型。

因此,使用{}向联合中添加任何内容并不会真正添加任何有关该类型的信息-关于生成类型的属性仍然一无所知。

但是在此代码中推断{}为空对象文字的类型

const getSomething = (t: Test) => t['key'] || {}

确实会导致信息丢失,因为已知 value {}没有属性,因此,如果结果类型具有任何属性,则它们必须来自{{1} }和Something的类型必须全部为a

也许将来TypeScript可以使用exact types处理此问题,但是到目前为止,您发现了一种可能的解决方法。

如果您对空对象使用类型断言string, 之所以可以得到预期的结果,是因为现在通过检查联合类型成员的通用属性并采用其类型的联合来计算结果类型。因此,as {[n: string]: undefined}具有Test作为属性类型,而Something来自类型声明,将undefined作为结果属性类型。

ConventionallySomething | undefined类型而不是never,因此您可以定义

undefined

它再次按预期工作,因为type StricterEmptyObject = { [n in string]?: never }; never相反,而{}的并集为never | undefined | Something

undefined | Something