打字稿:类型系统无法证明看起来显然是正确的东西



以下给出了getWrapper中的编译错误:

type Wrapper<K> = {
    value: K
}
type Wrappers = {
    [K in 'henk' | 'piet']: Wrapper<K>
}
const wrappers: Wrappers = {
    'henk': { value: 'henk' },
    'piet': { value: 'piet' }
}
function getWrapper<K extends keyof Wrappers>(k: K): Wrapper<K> {
    return wrappers[k]
}

它说DAT认为wrappers[k]Wrapper<'henk'> | Wrapper<'piet'>。它应该能够确定wrappers[k]实际上是Wrapper<K>。我可以帮助打字稿弄清楚吗?

更新:2019-05-30 TypeScript 3.5的发行版引入了更智能的联合类型检查,但没有解决此问题,可能是因为这是使用通用类型K而不是联合的结合已知的具体类型。因此,到目前为止,下面的解决方案没有变化。


我很确定您的问题是Typescript不会按照您的期望减少工会。例如,您可能期望以下内容有效:

declare const innerUnion: { foo: string | number };
const outerUnion: { foo: string } | { foo: number } = iU; // error

但事实并非如此。Typescript不会积极地将outerUnion的类型减少到innerUnion的类型。编译器没有自动这样做的原因似乎是实用主义:在许多情况下,这种减少是错误的,因为还有另一个无法合并的属性:

declare const iU: { foo: string | number, bar: string | number };
const oU: { foo: string, bar: string } | { foo: number, bar: string } = iU; // error

上面的错误是一个很好的错误,因为也许iU{ foo: 0, bar: '' }

打字稿认为K可以是'henk' | 'piet'类型,因此该函数的输出可以是Wrapper<'henk' | 'piet'>,但返回值是类型Wrapper<'henk'> | Wrapper<'piet'>。而且,由于上述减少工会是打字稿不做的事情,因此说有错误。


so,为什么返回值类型Wrapper<'henk'> | Wrapper<'piet'>?因为用密钥联合 do 将索引到对象中导致该对象的属性值的结合。

这建议解决您的问题的解决方案,使用查找类型表示索引操作:

function getWrapper<K extends keyof Wrappers>(k: K): Wrappers[K] {
    return wrappers[k]; // okay
}

我认为这做了您想要的。希望有帮助;祝你好运!

相关内容

最新更新