是否可以将较大类型的部分提取为子类型?
Is it possible to extract parts of a larger type into subtypes?
如果你有 3 个子类型将它们组合成一个大的子类型是微不足道的:
type Strings = {
a: string;
b: string;
c: string;
...
};
type Numbers = {
one: number;
two: number;
...
};
type Booleans = {
True: boolean;
...
};
type All = Strings & Numbers & Booleans;
但是如果您从组合类型开始呢?
type All = {
a: string;
b: string;
c: string;
one: number;
two: number;
True: boolean;
...
}
是否可以根据每个键值的类型将All
拆分为上述3个子类型?
我想也许这行得通,但行不通
type noNumbers= Exclude<All, { [key: string]: number }>;
不确定是否有更简单或更好的方法,但这行得通。
type PickOut<T, K> = {
[P in keyof T]: T[P] extends K ? P : never
}[keyof T]
type NumberKeys = PickOut<All, number>
type BooleanKeys = PickOut<All, boolean>
type StringKeys = PickOut<All, string>
type justNumbers = Pick<All, NumberKeys>
type justBooleans = Pick<All, BooleanKeys >
type justStrings = Pick<All, StringKeys >
我们可以自定义类型级别的功能,以实现或省略按值类型或按值类型选择。在两个选项下方:
// picks given values
type PickByValue<T, V, _Keys extends keyof T = {
[K in keyof T]: T[K] extends V ? K : never
}[keyof T]> = Pick<T, _Keys>
type Numbers = PickByValue<All, number>
type Strings = PickByValue<All, string>
// omits given values
type OmitByValue<T, V, _Keys extends keyof T = {
[K in keyof T]: T[K] extends V ? K : never
}[keyof T]> = Omit<T, _Keys>
type Bools = OmitByValue<All, number | string>
成功的关键是union类型如何踩never
,它是|
运算符的中立元素,也就是说它只是被跳过了,对类型没有影响。考虑小证明:
type X = 'a' | never | 'b' // evaluates to just 'a' | 'b'
感谢我们可以使用 never
来跳过一些键。这在这部分是完全可见的:
{
[K in keyof T]: T[K] extends V ? K : never
}[keyof T]
真正发生的事情是——我们创建映射类型,其值等于键,但前提是值类型是正确的,否则我们使用 never
,然后我们通过索引获取这些值 [keyof T]
。让我们逐步回顾一下发生了什么:
- 映射类型使映射类型
key-> (key | never)
[keyof T]
将所有值类型收集为联合(不考虑 never
元素)
- 我们现在拥有所有未被
never
跳过的键
- 我们在实用程序类型
Pick
或 Omit
中使用这些键
如果你有 3 个子类型将它们组合成一个大的子类型是微不足道的:
type Strings = {
a: string;
b: string;
c: string;
...
};
type Numbers = {
one: number;
two: number;
...
};
type Booleans = {
True: boolean;
...
};
type All = Strings & Numbers & Booleans;
但是如果您从组合类型开始呢?
type All = {
a: string;
b: string;
c: string;
one: number;
two: number;
True: boolean;
...
}
是否可以根据每个键值的类型将All
拆分为上述3个子类型?
我想也许这行得通,但行不通
type noNumbers= Exclude<All, { [key: string]: number }>;
不确定是否有更简单或更好的方法,但这行得通。
type PickOut<T, K> = {
[P in keyof T]: T[P] extends K ? P : never
}[keyof T]
type NumberKeys = PickOut<All, number>
type BooleanKeys = PickOut<All, boolean>
type StringKeys = PickOut<All, string>
type justNumbers = Pick<All, NumberKeys>
type justBooleans = Pick<All, BooleanKeys >
type justStrings = Pick<All, StringKeys >
我们可以自定义类型级别的功能,以实现或省略按值类型或按值类型选择。在两个选项下方:
// picks given values
type PickByValue<T, V, _Keys extends keyof T = {
[K in keyof T]: T[K] extends V ? K : never
}[keyof T]> = Pick<T, _Keys>
type Numbers = PickByValue<All, number>
type Strings = PickByValue<All, string>
// omits given values
type OmitByValue<T, V, _Keys extends keyof T = {
[K in keyof T]: T[K] extends V ? K : never
}[keyof T]> = Omit<T, _Keys>
type Bools = OmitByValue<All, number | string>
成功的关键是union类型如何踩never
,它是|
运算符的中立元素,也就是说它只是被跳过了,对类型没有影响。考虑小证明:
type X = 'a' | never | 'b' // evaluates to just 'a' | 'b'
感谢我们可以使用 never
来跳过一些键。这在这部分是完全可见的:
{
[K in keyof T]: T[K] extends V ? K : never
}[keyof T]
真正发生的事情是——我们创建映射类型,其值等于键,但前提是值类型是正确的,否则我们使用 never
,然后我们通过索引获取这些值 [keyof T]
。让我们逐步回顾一下发生了什么:
- 映射类型使映射类型
key-> (key | never)
[keyof T]
将所有值类型收集为联合(不考虑never
元素)- 我们现在拥有所有未被
never
跳过的键
- 我们在实用程序类型
Pick
或Omit
中使用这些键