联合分散
大约 2 分钟
分布式条件类型
相关信息
当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型
比如
type Union = 'a' | 'b' | 'c';
// 我们大写其中的 a
// ts会把联合类型的每一个元素单独传入做类型计算,最后合并
type UppercaseA<Item extends string> = Item extends 'a'
? Uppercase<Item>
: Item;
type result = UppercaseA<Union>;
CamelcaseUnion
实现 'aa_aa_aa' | 'bb_bb_bb'
=> 'aaAaAa' | 'bbBbBb'
我们之前实现的 CamelcaseArr
是不是需要去取 每个元素
, 但是对于 联合类型
我们是不需要每个都去取的, 因为 ts 会把每一个元素单独传入
type CamelcaseUnion<Str extends string> =
Str extends `${infer First}_${infer NeedUpper}${infer Rest}`
? `${First}${Uppercase<NeedUpper>}${CamelcaseUnion<Rest>}`
: Str;
type result = CamelcaseUnion<'aa_aa_aa' | 'bb_bb_bb'>;
IsUnion
实现 'a' | 'b' | 'c'
=> true
type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;
type result = IsUnion<'a' | 'b'>;
注
当 A 是联合类型时
- A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义
- A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型
BEM
bem 是 css 命名规范,用 block__element--modifier
的形式来描述某个区块下面的某个元素的某个状态的样式。
那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名
type BEM<
Block extends string,
Element extends string[],
Modifier extends string[],
> = `${Block}__${Element[number]}--${Modifier[number]}`;
type result = BEM<'decade', ['aaa', 'bbb'], ['success', 'error']>;
注
Element 和 Modifiers 通过索引访问
来变为联合类型
AllCombinations
实现 'A' | 'B'
=> 'A' | 'B' | 'BA' | 'AB'
// 先实现基础的
type Combination<A extends string, B extends string> =
| A
| B
| `${A}${B}`
| `${B}${A}`;
type AllCombinations<A extends string, B extends string = A> = A extends A
? Combination<A, AllCombinations<Exclude<B, A>>>
: never;
type result = AllCombinations<'a' | 'b' | 'c'>;
思路
全排列 最简单的部分 一定是两两之间
的全排列, 只有四种, 所以 Combination
就是这么实现的
A extends A 获取到 然后 Combination<A, AllCombinations<Exclude<B, A>>>
这里面的 A
就是单独的 'a'
, 'b
, 'c'
Exclude<B, A>
是去掉 B中和A相交的那部分
,
总结
联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型