假设我有一个这样的联合类型:
{id: 'A', format: 'foo' | 'bar, value: 1 | 2}
|
{id: 'B', format: 'baz', value: 3 | 4}
|
{id: 'C', format: 'qux', value: 'hello' | 'goodbye'}
我希望这种类型的每个对象都保持其内部关系,以便如果id
等于A
,则格式必须是foo
或bar
等。
现在,我想创建另一个与Entry
相关的类型,它具有相同的id
属性,但是format
是可选的,value
应该省略。我们称之为EntryInput
(想象一个函数,你提供一个EntryInput
作为输入参数,并返回一个Entry
)。相反,我想从Entry
类型创建它。然而,一旦你在这样的联合体上应用Pick
,所有属性都会混合在一起形成{id: 'A' | 'B' | 'C'; format: 'foo' | 'bar' | 'baz' | 'qux'; value: 1 | 2 | 3 | 4 | 'hello' | 'goodbye'}
。例如,请参见https://github.com/microsoft/TypeScript/issues/28339
我知道我可以创建一个泛型类型Entry<Id extends 'A' | 'B' | 'C'>
并创建一个类似createEntry<Id>(input: EntryInput<Id>): Entry<Id>
的函数来维护函数的输入类型和输出类型之间的关系,其中Id
是从提供的值推断出来的,因此强制format
正确地与id
相关,但我需要的不是泛型类型,我需要一个联合类型,这样我就可以声明
const entries: Entry[] = [ ... ]
...并且这里的每个条目都是一致的,因此id
的值决定了format
和value
的可能值。如果对泛型类型这样做,属性将再次分布,因此{id: 'A', format: 'qux', value: 'hello}
是有效的Entry
。
如何设置类型,以便从Entry
派生类型EntryInput
,同时保持属性之间的内部关系不变?
2条答案
按热度按时间cbeh67ev1#
从以下联合类型开始:
我们可以通过使用分配条件类型对其进行操作来创建所需形式的新并集,如下所示:
条件类型仅在被检查的类型是generic类型参数时分布在联合上,
Entry
不是泛型。如果你尝试Entry extends ⋯ ? ⋯ : never
,它不会分发。Entry2
定义使用了一个小技巧,条件类型infer
可以“复制”Entry
转换为泛型类型参数E
,这样检查E extends ⋯ ? ⋯ : never
确实是分布式的。(If这个技巧太奇怪了,你可以重构成
在这里,你创建一个泛型类型函数,只使用它一次。)
Playground链接到代码
kmbjn2e32#
我自己的解决方案是这样的。我需要的是id到{format,value}的Map,以使用Map类型派生其他类型,这将分布在键上: