# 21106-组合键类型
# 题目描述
编写一个类型,把给定的修饰键数组 ModifierKeys 做两两组合。要求:
- 同一种修饰键组合不能重复出现;
ModifierKeys中前面的键优先级高于后面的键,例如'cmd ctrl'合法,但'ctrl cmd'不合法。
type ModifierKeys = ['cmd', 'ctrl', 'opt', 'fn'];
type A = Combs<ModifierKeys>;
// 'cmd ctrl' | 'cmd opt' | 'cmd fn'
// | 'ctrl opt' | 'ctrl fn' | 'opt fn'
# 分析
约束"前者优先级高"等价于只允许"左边 index 小、右边 index 大"的组合。换言之,对于元组里每一个元素 F,它可以和它右边的任意一个元素配对。
拆两步:
- 拆出首项
F,把F和剩余元组R中的每一项都配对一次:`${F} ${R[number]}`。 - 对剩余元组
R递归同样的过程。
# 题解
type Combs<T extends string[]> = T extends [
infer F extends string,
...infer R extends string[],
]
? `${F} ${R[number]}` | Combs<R>
: never;
解读:
F固定是前一位,R[number]作为"后一位"的联合,模板字面量对联合自动分发,一次性铺开所有F-Rest配对。- 对
R继续递归,直到R = []→R[number]为never,整支返回never退出。
# 验证
type M = ['cmd', 'ctrl', 'opt', 'fn'];
type R = Combs<M>;
// 'cmd ctrl' | 'cmd opt' | 'cmd fn' | 'ctrl opt' | 'ctrl fn' | 'opt fn'
# 知识点
R[number]把元组展成联合是最廉价的方式,见 类型转换大集合。- 模板字面量对联合自动分发,配对
`${F} ${R[number]}`一步到位。