打字稿:将标记的联合转换为联合类型
Posted
技术标签:
【中文标题】打字稿:将标记的联合转换为联合类型【英文标题】:Typescript: convert a tagged union into an union type 【发布时间】:2020-10-16 20:21:21 【问题描述】:我有以下标记的联合接口
interface Example
a: TypeA;
b: TypeB;
作为输出,我想将此标记的联合转换为联合类型,例如:
type oneOf<T> = ...
在哪里
var example: oneOf(Example); // would be a: TypeA | b : TypeB
我无法将类型键映射到只有键作为参数的对象中。有什么想法吗?
【问题讨论】:
【参考方案1】:您可以通过以下组合来做到这一点:
Distributive conditional types Mapped typesinterface Example
a: string;
b: number;
type SingleProperty<T, K extends keyof T> = K extends any ? [Prop in K]: T[Prop] : never
type UnionOfProperties<T> = [K in keyof T]: SingleProperty<T, K> [keyof T];
type ExamplePropertiesUnion = UnionOfProperties<Example>
这将返回预期:
type ExamplePropertiesUnion =
a: string;
|
b: number;
虽然以上是正确的,但 TS 将允许以下情况
var t: ExamplePropertiesUnion = a: "", b: 42
这不是我们通常想要的:
下面是更严格类型检查的变体
type FixTsUnion<T, K extends keyof T> = [Prop in keyof T]?: Prop extends K ? T[Prop]: never
type oneOf<T> = [K in keyof T]: Pick<T, K> & FixTsUnion<T, K>[keyof T];
// ok
var z1: oneOf<Example> = a: "" ;
// ok
var z2: oneOf<Example> = b: 5 ;
// error
var z3: oneOf<Example> = a: "", b: 34 ;
// error
var z4: oneOf<Example> = ;
Try it here
查看问题:
TypeScript: Map union type to another union type Transform union type to intersection type【讨论】:
虽然这可行,但我现在想知道为什么var t: a: string | b: number = a: "", b: 42
不会引发错误。
我认为 TS 不支持联合类型的多余属性检查。我设法在谷歌上搜索了一些建议:github.com/microsoft/TypeScript/issues/23535github.com/Microsoft/TypeScript/issues/14094你可以尝试明确地解决这个问题:var t: a: string, b: never | b: number, a: never = a: "", b: 42
好主意,但任何简单的做作都会失败,例如:var t: a: string , b: never | a: never, b: string = a: ""
我的错。很抱歉造成混乱。
因为 b 应该是数字。我编辑了你的答案,你应该得到所有的荣誉;-)【参考方案2】:
type EntryUnion<T> = [K in keyof T]: [Q in K]: T[Q] [keyof T];
这实际上与
相同type EntryUnion<T> = [K in keyof T]: Pick<T, K> [keyof T];
但是每当我使用诸如 Pick 之类的 util 类型时,Intellij 和 VS Code 中的类型推断都会在 Pick 处停止并拒绝进一步扩展。尽管它们在执行分配时执行类型正确性时所做的工作完全相同,但当出现问题时,使用 Pick 的类型定义不正确的地方就不那么明显了(除非您非常熟悉 Pick 的作用)
【讨论】:
嗨,我记下了快捷方式,您的解决方案也可以确保至少存在一个键,但不能确保没有重复项(键上的独占联合)check here 是的,你完全正确。然而,对我来说,这个特殊的问题涉及严格性和清晰性之间的权衡。实际上,这里最严格的类型定义应该是 (inferred as) a: string, b: never | a: never, b: number
。但它缺乏清晰性,尤其是当您有更多案例以及分配错误并且代码无法编译时。与将类型定义为 a: string | b: number
相比,IDE 的帮助较小。但是您仍然是对的,我找不到在打字稿中表达独占键的简单方法以上是关于打字稿:将标记的联合转换为联合类型的主要内容,如果未能解决你的问题,请参考以下文章