对此有不同的方法。这是一种工作和不工作的方式。可能还有其他方式继续,但我现在时间紧迫:
type SameLength<T> = { [K in keyof T]: any };
type Cyclic<T extends readonly any[], C extends readonly any[]> = readonly [] |
(T extends [...SameLength<C>, ...infer U] ? readonly [...U, ...C] : readonly [...C]);
function someFunction<T extends readonly (string | number)[]>(
...args: T & Cyclic<T, [string, number]>
) { ... }
这应该主要从打电话的人的角度来进行。这个想法是
args
Cyclic<[A, B, C, D], [string, number]
[C, D, string, number]
. 如果
[A, B, C, D]
都是一样的,这意味着它必须是一样的
[string, number, string, number]
实际上,函数允许和不允许按您想要的方式调用。
someFunction(); // okay
someFunction("a"); // error
someFunction("a", 1); // okay
someFunction("a", "b"); // error
someFunction("a", 1, "b", 2); // okay
someFunction("a", 1, "b", 2, "c", 3); // okay
不幸的是,这些错误并不是特别有用,特别是因为它们都出现在第一个参数上(这是一个bug,
microsoft/TypeScript#28505
),他们抱怨被分配给
never
. 这
内部
实施
在功能方面,情况更糟。编译器不知道什么类型
T
将是,它不能一般地推断其他元素都是
string
number
. 你所得到的只是:
function someFunction<T extends readonly (string | number)[]>(
...args: T & Cyclic<T, [string, number]>
) {
const a = args[0] // string
const b = args[1] // number
const c = args[2] // string | number ð¢
}
因此,在函数内部,您需要使用
assertion
args[2*k]
是一个
string | undefined
args[2*k+1]
是一个
number | undefined
所以这还不够完善,我建议在生产代码中使用它。
Playground link to code
type StringNumberAlternating<L extends number,
A extends readonly any[] = readonly []> = (string | number)[] & (
undefined extends [...A][L] ? A['length'] extends L ? A :
StringNumberAlternating<L, [string, number, ...A]> : A)
function someFunction<T extends StringNumberAlternating<T['length']>>(
...args: T
) { }
Playground link to code
type SN<T extends readonly any[] = readonly []> = readonly [] | readonly [string, number, ...T]
type SNT<L extends number, A extends readonly any[] = readonly []> =
A | (A['length'] extends L ? never : SNT<L, readonly [string, number, ...A]>);
type StringNumberTuples = SNT<20>; // max length of 20
function someFunction(...args: StringNumberTuples) {
const a = args[0] // string | undefined
const b = args[1] // number | undefined
const c = args[2] // string | undefined
const d = args[Math.floor(Math.random() * 100)] // string | number ð¤·ââï¸
}
这有很好的错误消息(除了由于microsoft/TypeScript#28505的原因,它们始终在第一个参数上),并且函数签名不再是通用的,因此更简单。主要的限制是你必须选择一些最大长度来支撑;这有点像使用重载,除了你可以只传递一个数字,比如20,而不是写10个重载签名。
Playground link to code