Bir*_*sky 3 types functional-programming typescript typescript2.0
我希望TypeScript在映射到这样的联合时强制执行穷举:
type Union =
{ type: 'A', a: string } |
{ type: 'B', b: number }
Run Code Online (Sandbox Code Playgroud)
Union事件处理程序:
const handle = (u: Union): string =>
theMap[u.type](u);
Run Code Online (Sandbox Code Playgroud)
如果在这里我们能以某种方式从TypeScript获得详尽的检查,那就太好了:
const theMap: { [a: string]: (u: Union) => string } = {
A: ({a}: { type: 'A', a: string }) => 'this is a: ' + a,
B: ({b}: { type: 'B', b: number }) => 'this is b: ' + b
};
Run Code Online (Sandbox Code Playgroud)
给定theMap定义的类型,很难(或者可能不可能)哄骗TypeScript,为您提供一种方法来表达详尽性检查(Extract<U, X>对于每个组合类型的联合只包含一个处理程序)和健全性约束(每个处理程序U都是为联盟的特定组成类型).
但是,可以X根据更一般的类型进行定义,您也可以从中表达上述约束.让我们先看一下更通用的类型:
type Union = { type: "A"; a: string } | { type: "B"; b: number };
const theMap: {
[K in Union["type"]]: (u: Extract<Union, { type: K }>) => string
} = {
A: ({ a }) => "this is a: " + a,
B: ({ b }) => "this is b: " + b
};
Run Code Online (Sandbox Code Playgroud)
这里theMap(u.type)(u)是从theMap(u.type)原始属性u到组成类型的映射,从中theMap(u.type)删除.从此,u相当于Union.
让我们在类型映射上定义一些操作,如theMap:
const handle = (u: Union): string =>
(theMap[u.type] as (v: Union) => string)(u); // need this assertion
Run Code Online (Sandbox Code Playgroud)
您可以验证这theMap相当于Union:
const handle = (u: Union): string =>
u.type === "A" ? theMap[u.type](u) : theMap[u.type](u); // redundant
Run Code Online (Sandbox Code Playgroud)
此外,定义BaseTypes:
type BaseTypes = {
A: { a: string };
B: { b: number };
}
Run Code Online (Sandbox Code Playgroud)
这需要一个关键type并产生联合的组成部分Union.所以,type是工会的一条腿,Union是其他,和他们一起做起来({type: 'A'} & BaseTypes['A']) | ({type: 'B'} & BaseTypes['B']).
现在我们可以定义类型BaseTypes:
type DiscriminatedType<M, K extends keyof M> = { type: K } & M[K];
type DiscriminatedTypes<M> = {[K in keyof M]: DiscriminatedType<M, K>};
type DiscriminatedUnion<M, V=DiscriminatedTypes<M>> = V[keyof V];
Run Code Online (Sandbox Code Playgroud)
它是一个映射类型,包含每种类型的一个属性Union,它是从特定类型到a 的函数DiscriminatedUnion<BaseTypes>.这是详尽的:如果你离开了一个NarrowedFromUnion或K,或把type功能上的NarrowedFromUnion<'A'>属性,编译器会抱怨.
这意味着我们能够省略上明确标注NarrowedFromUnion<'B'>和Union,因为类型theMap现在执行此约束.这很好,因为代码中的显式注释不是很安全; 你可能已经切换了注释而没有被编译器警告,因为它只知道输入是一个Union.(这种不合理的类型缩小函数参数称为双变量,它在TypeScript中是混合的祝福.)
现在我们应该string在传入A的B参数中使用泛型,因此编译器将检查我们是否正在使用它做一些安全的事情:
type Union = DiscriminatedUnion<BaseTypes>
Run Code Online (Sandbox Code Playgroud)
如果你留下旧签名(B),它会抱怨,除非你用类型断言使它静音.
好的,那是很多.希望能帮助到你.祝好运!