[英]Mapping types in TypeScript
Is it possible in TS to transform this type TS中是否可以转换这种类型
type input = {
a: 1;
b: 2;
c: 3;
};
into this type成这种类型
type output = { a: 1 } | { b: 2 } | { c: 3 };
? ?
You want a type function that converts Input
to Output
;您需要一个将
Input
转换为Output
的类型函数; let's call it " Split<T>
", for want of a better name.让我们称它为“
Split<T>
”,因为需要一个更好的名字。 Here's one approach:这是一种方法:
type Split<T extends object> =
{ [K in keyof T]-?: Pick<T, K> }[keyof T];
On the inside we're using the Pick<T, K>
utility type to represent the same type as T
but only with the keys from K
.在内部,我们使用
Pick<T, K>
实用程序类型来表示与T
相同的类型,但仅使用来自K
的键。 So Pick<Input, "a">
is {a: 1}
:所以
Pick<Input, "a">
是{a: 1}
:
type Test = Pick<Input, "a">
// type Test = { a: 1; }
On the outside is a distributive object type (as coined in microsoft/TypeScript#47109 ), which is what you get when you make a mapped type over some set of keys and then immediately index into it with the same set of keys.外部是分布式对象类型(如microsoft/TypeScript#47109中所创造的),当您在一组键上创建映射类型,然后立即使用同一组键对其进行索引时,您会得到这种类型。 I
我
Distributive object types let you take a type function F<K>
for some keylike type K
, and produce the union of F<K>
for each union member K
in some set of keys.分布式对象类型让您可以为某些类似键的类型
K
采用类型函数F<K>
,并为某些键集中的每个联合成员K
生成F<K>
的联合。 In the above case, keyof T
is the set of keys.在上述情况下,
keyof T
是键的集合。 So the above will compute the union of Pick<T, K>
for each K
in keyof T
, which is what you want:因此,上面将为
keyof T
中的每个K
计算Pick<T, K>
的并集,这就是您想要的:
type Input = {
a: 1;
b: 2;
c: 3;
};
type Output = Split<Input>;
// type Output = Pick<Input, "a"> | Pick<Input, "b"> | Pick<Input, "c">
If you don't like seeing Pick
in the IntelliSense output, you can inline the definition of Pick<T, K>
into Split<T>
:如果您不喜欢在 IntelliSense 输出中看到
Pick
,您可以将Pick<T, K>
的定义内联到Split<T>
中:
type Split<T extends object> =
{ [K in keyof T]-?: { [P in K]: T[P] } }[keyof T];
type Output = Split<Input>;
// type Output = { a: 1; } | { b: 2; } | { c: 3; }
You can do this:你可以这样做:
type input = {
a: 1;
b: 2;
c: 3;
};
type output = { a: 1 } | { b: 2 } | { c: 3 };
let i : input = {
a: 1,
b: 2,
c: 3
};
let o : output;
let {a, b, c} = i;
o = {a} || {b} || {c};
Honestly, I have no idea how to implement this from scratch.老实说,我不知道如何从头开始实现它。 But here's a library that does exactly this and much more (ts-toolbelt):
但这里有一个库可以做到这一点以及更多(ts-toolbelt):
import { Object } from 'ts-toolbelt';
type Input = {
a: 1;
b: 2;
c: 3;
};
type Output = Object.Either<Input, keyof Input>;
Not sure if this scales to more complicated input
types, might get weird with nested things不确定这是否可以扩展到更复杂的
input
类型,嵌套的东西可能会变得很奇怪
type input = {
a: 1;
b: 2;
c: 3;
};
// given key K, construct {[K]: T[K]}
type m2<T, K extends keyof T> = {[k in K]: T[k]}
// for each key K in T, construct {[K]: T[K]}, and union the results
type m1<T, K extends keyof T> = K extends any ? m2<T, K> : never;
type map<T> = m1<T, keyof T>;
type result = map<input>
declare const result : result;
if ("a" in result) {
result.a // type 1
}
else if ("b" in result) {
result.b; // type 2
}
else {
result.c // type 3
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.