TypeScript是否支持带重复类型模式的剩余参数?
实现支持重复模式的类型安全可变参数函数
需求说明
需要编写类型安全的函数,接受1组及以上遵循重复模式的平铺可变参数:
- 示例1:参数需为
string+number对,空调用、参数个数为奇数时报错,个数为偶数且符合类型时通过 - 示例2:参数需为
"a"|"b"|"c"+number+number三元组,参数个数不为3的正整数倍时报错,类型不符合时报错 - 支持任意长度的重复模式,模式元素可以是联合、接口、交叉等任意类型
解决方案
1. 针对固定模式的实现(以string+number对为例)
先定义基础模式元组,再通过递归生成所有符合要求的参数元组:
// 定义基础模式:string+number对 type StringNumberPair = [string, number]; // 递归生成1组及以上的重复模式元组 type RepeatedStringNumberPairs = StringNumberPair | [...StringNumberPair, ...RepeatedStringNumberPairs]; // 函数声明 declare function repeatingRestParamsPairs(...args: RepeatedStringNumberPairs): void; // 测试用例 repeatingRestParamsPairs(); // 报错:参数个数为0,不符合至少1组的要求 repeatingRestParamsPairs("a"); // 报错:参数个数为1,不是2的倍数 repeatingRestParamsPairs("a", 1); // 编译通过:恰好1组 repeatingRestParamsPairs("a", 1, "b"); // 报错:参数个数为3,不是2的倍数 repeatingRestParamsPairs("a", 1, "b", 2); // 编译通过:2组
2. 通用重复模式实现(支持任意长度的模式)
定义通用递归类型,适配任意结构的重复模式:
// 通用重复模式类型:生成模式P的1组及以上平铺元组 type RepeatPattern<P extends any[]> = P extends [] ? never : P | [...P, ...RepeatPattern<P>]; // 示例:三元组模式 type FirstInPattern = "a" | "b" | "c"; type TriplePattern = [FirstInPattern, number, number]; type RepeatedTriplePattern = RepeatPattern<TriplePattern>; // 函数声明 declare function repeatingRestParamsTriple(...args: RepeatedTriplePattern): void; // 测试用例 repeatingRestParamsTriple(); // 报错 repeatingRestParamsTriple("a"); // 报错 repeatingRestParamsTriple("a", 1); // 报错 repeatingRestParamsTriple("a", 1, 2); // 编译通过:1组三元组 repeatingRestParamsTriple("foo", 1, 2); // 报错:第一个参数不符合FirstInPattern类型 repeatingRestParamsTriple("a", 1, 2, "b", 3); // 报错:参数个数为5,不是3的倍数 repeatingRestParamsTriple("a", 1, 2, "b", 3, 4); // 编译通过:2组三元组
原理说明
RepeatPattern<P>是递归条件类型:若模式P为空则返回never(禁止空参数),否则要么是模式P本身,要么是P拼接另一个符合RepeatPattern<P>的元组- 该类型会自动生成所有长度为模式长度正整数倍的元组联合,TypeScript会在函数调用时自动匹配参数的长度和类型,实现类型安全
- 支持任意复杂的模式元素:联合类型、接口、交叉类型、函数类型等都可以作为模式的组成部分
内容的提问来源于stack exchange,提问作者Daniel Kaplan
相关产品推荐
相关产品推荐

