# 4260-实现全组合
# 题目描述
Implement type AllCombinations<S>
that return all combinations of strings which use characters from S
at most once.
For example:
type AllCombinations_ABC = AllCombinations<'ABC'>;
// should be '' | 'A' | 'B' | 'C' | 'AB' | 'AC' | 'BA' | 'BC' | 'CA' | 'CB' | 'ABC' | 'ACB' | 'BAC' | 'BCA' | 'CAB' | 'CBA'
# 分析
这一题是实现全组合,之前有一题是实现 全排列。巧妙的借助联合的分发特性以很少的代码实现了全排列。
那么全组合呢?说实话,全排列全组合这几道题我在做的时候也头大,思路也很少,因为感觉就是挺难的。
也是重复借助联合的分发特性进行实现。第一步,将字符转成联合类型,可以参考 531-字符转联合。
第二步,触发分发特性,选择一个元素,对剩余元素进行递归。这一过程中,由于分发后的 T 仅仅表示当前的元素,所以还需要增加一个参数保留完整的字符。
可以直接看题解。
# 题解
// string 转 联合
// 同时塞进了一个 空字符,这是因为所有组合中包含了全空这个选项,和排列不同
type StringToUnion<T extends string> = T extends `${infer F}${infer R}`
? F | StringToUnion<R>
: '';
type AllCombinations<
S extends string,
// 默认值是转换后的元组,之后 S 的值其实并不重要
U extends string = StringToUnion<S>,
C extends string = U,
> =
// 触发分发特性
U extends any
? // 组成新的联合类型,注意 Exclude<C, U>,此时的 U 是当前元素,C 是当前元组所有元素,故 Exclude<C, U> 就是剩余元素
U | `${U}${AllCombinations<'', Exclude<C, U>>}`
: never;
细心的同学可能会发现,这里没有处理 never 的场景,这是因为 A | never = never,不像全排列中 [1, ...never] = never
所以不需要处理该情况。