Typescript:类型系统无法证明某些看起来显然是正确的东西

Typescript:类型系统无法证明某些看起来显然是正确的东西,typescript,Typescript,下面给出了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 ex

下面给出了
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]
}
类型包装={
值:K
}
类型包装={
[K in'henk'|'piet']:包装纸
}
常量包装器:包装器={
'henk':{value:'henk'},
'piet':{value:'piet'}
}
函数getWrapper(k:k):包装器{
返回包装器[k]
}

它说,
wrappers[k]
Wrapper | Wrapper
。它应该能够计算出
wrappers[k]
实际上是
Wrapper
。我可以帮助Typescript解决这个问题吗?

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


我很确定你的问题就是你所期望的那样。例如,您可能希望以下各项起作用:

declare const innerUnion: { foo: string | number };
const outerUnion: { foo: string } | { foo: number } = iU; // error
但事实并非如此。TypeScript不会主动将
外部运行类型
减少为
内部联合类型
。编译器不自动执行此操作的原因似乎是出于实用主义:在许多情况下,这样的缩减是错误的,因为存在另一个无法合并的属性:

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:'}

TypeScript认为
K
可以是
'henk'|'piet'
类型,因此函数的输出可以是
包装器
,但返回值的类型是
包装器|包装器
。因为上面的联合缩减是TypeScript没有做的,所以它说有一个错误


那么,为什么返回值的类型为
Wrapper | Wrapper
?因为索引到具有键并集的对象会导致该对象的属性值并集

这为您的问题提供了一个解决方案,请使用表示该索引操作的:

function getWrapper<K extends keyof Wrappers>(k: K): Wrappers[K] {
    return wrappers[k]; // okay
}
函数getWrapper(k:k):包装器[k]{ 返回包装器[k];//好的 }
我想这正是你想要的。希望有帮助;祝你好运

这是一个非常彻底的回答!非常感谢。从概念上讲,我还有一个问题。因为它对
Wrappers
的了解比它只知道键和值多一点。它知道(或应该知道)每个键
K
都属于一个值
Wrapper
。为什么它不使用这个信息,而是说“我所知道的关于这个值的一切就是它是
Wrapper
或者
Wrapper
?我可以用
函数getWrapper(k:k):Wrappers[k]{return{value:'piet'}愚弄代码”
,因此它实际上不起作用,不幸的是。
K
参数的值可以是
'henk'|'piet'
。这里,请看:
getWrapper(Math.random())至于在函数的实现中愚弄代码,这似乎是另一个问题,可能值得作为TS bug提交。”K参数的值可以是“henk”|“piet”