映射类型:属性 到项目
mapped type: Property to item
考虑这段代码:
type A = { k: 'a.a', u: string } | { k: 'a.b', v: string };
type B = { k: 'b.a', w: number } | { k: 'b.b', x: number };
列表中的每个项目都有一个键k
,它是唯一的。所以
type AandB = A | B;
产生整体联合。
我正在尝试创建这样的映射类型:
type Map = {
[k in AandB['k']]: <the respective item in AandB> AandB[k] wont work.
}
如果应用,编译器应该验证这样的对象:
const m: Map = {
"a.a": { k: 'a.a', u: 'test' }
…
…
…
}
如何获得相应的物品?
这可以通过一些 Type Generic 技巧来实现:
// Get the type of a union based on the value (V) and lookup field (K)
type DiscriminateUnion<
T,
K extends keyof T,
V extends T[K]
> = T extends Record<K, V> ? T : never;
然后:
type Map = {
[k in AandB['k']]: DiscriminateUnion<AandB, 'k', k>;
};
那么,地图应该按照你指出的那样严格输入:
const map: Map = {
'a.a': { k: 'a.a', u: 'example' },
'b.a': { k: 'b.a', w: 0 },
'b.b': { k: 'b.b', x: 1 },
'a.b': { k: 'a.b', v: 'Example' }, // TS won't let you change the ids
// or variable names unless they match the respective object key type.
};
为什么这样做有效?
重要的是要将联合类型理解为不仅仅是一种类型,而是多种类型的数组。
当进行以下比较时:
T extends Record<K, V>? T : never
我们实际上是将此联合的每种类型与以下三元(if 语句)进行比较。
由于 Record
表示一个对象,其中键的类型为 K
,值的类型为 V
,我们最终在 AandB
中对每种类型进行循环并且只返回 K: 'k'
等于指定键 V
的类型,可能是 a.a, b.b, etc
,否则返回 never 如果至少返回一个元素,则忽略该类型。
考虑这段代码:
type A = { k: 'a.a', u: string } | { k: 'a.b', v: string };
type B = { k: 'b.a', w: number } | { k: 'b.b', x: number };
列表中的每个项目都有一个键k
,它是唯一的。所以
type AandB = A | B;
产生整体联合。
我正在尝试创建这样的映射类型:
type Map = {
[k in AandB['k']]: <the respective item in AandB> AandB[k] wont work.
}
如果应用,编译器应该验证这样的对象:
const m: Map = {
"a.a": { k: 'a.a', u: 'test' }
…
…
…
}
如何获得相应的物品?
这可以通过一些 Type Generic 技巧来实现:
// Get the type of a union based on the value (V) and lookup field (K)
type DiscriminateUnion<
T,
K extends keyof T,
V extends T[K]
> = T extends Record<K, V> ? T : never;
然后:
type Map = {
[k in AandB['k']]: DiscriminateUnion<AandB, 'k', k>;
};
那么,地图应该按照你指出的那样严格输入:
const map: Map = {
'a.a': { k: 'a.a', u: 'example' },
'b.a': { k: 'b.a', w: 0 },
'b.b': { k: 'b.b', x: 1 },
'a.b': { k: 'a.b', v: 'Example' }, // TS won't let you change the ids
// or variable names unless they match the respective object key type.
};
为什么这样做有效?
重要的是要将联合类型理解为不仅仅是一种类型,而是多种类型的数组。
当进行以下比较时:
T extends Record<K, V>? T : never
我们实际上是将此联合的每种类型与以下三元(if 语句)进行比较。
由于 Record
表示一个对象,其中键的类型为 K
,值的类型为 V
,我们最终在 AandB
中对每种类型进行循环并且只返回 K: 'k'
等于指定键 V
的类型,可能是 a.a, b.b, etc
,否则返回 never 如果至少返回一个元素,则忽略该类型。