我希望创建一个类型,表示那些在最后一个参数位置有类型T
的函数。可变参数元组类型看起来可以毫无问题地解决这个问题,但在我目前的方法中,像这样的类型:
type TasLastArg<T> = (...args: [...any, T]) => any;
args
论点是否崩溃为any[]
.其他地方也有类似的行为,让我认为这应该是可能的;目前不起作用的示例/为什么我认为这是可能的:
type TasFirstArg<T> = (...args: [T, ...any]) => any; // this appears to work as expected
type TasLastArg<T> = (...args: [...any, T]) => any; // would like for this to work
namespace T_in_first_place {
const ok : TasFirstArg<string> = (x:string, y: number, z: string) => { return 0; }
const correctly_fails : TasFirstArg<string> = (x:number, y: number, z: number) => { return 0; }
}
namespace T_in_last_place {
const ok : TasLastArg<string> = (x:number, y: number, z: string) => { return 0; }
const should_fail_but_does_not: TasLastArg<string> = (x:number, y: number, z: number) => { return 0; }
}
// there is some machinery that allows looking at the last type in a tuple:
type CheckStringIsLast<T extends any[]> = T extends [...infer first, string] ? true : false;
type it_checks_this_fine = CheckStringIsLast<[number, number, string]>; // true
type it_properly_rejects_this = CheckStringIsLast<[number, number, number]>; // false
这是不可能的,还是我错过了什么?
TypeScript 4.1 仅支持元组类型末尾的 rest 元素。 可变参数元组类型允许您编写[...any, T]
,但这只会折叠为any[]
。
当 TypeScript 4.2 发布时,它应该在开头或中间开始接受 rest 元素(但每个元组只有一个 rest 元素)。 请参阅 microsoft/TypeScript#41544 了解实现此目的的 PR。 此时,[...any, T]
将被解释为[...any[], T]
,意思是"任何末尾有T
的元组",如您所愿。
请注意,一旦支持此功能,您的示例就不会真正达到您的预期:
const ok : TasLastArg<string> = (x:number, y: number, z: string) => { return 0; } // error!
// -> ~~
// Target requires 3 element(s) but source may have fewer
这是一个错误,因为虽然目标函数确实需要string
作为其最后一个元素,但它不符合TasLastArg<string>
,它需要是一个接受任何以string
结尾的参数列表的函数。 这意味着您需要能够这样称呼它:
ok("shouldWork");
ok(1, 2, 3, 4, 5, 6, 7, true, new Date(), "shouldAlsoWork");
对于(x: number, y: number, z: string) => number
类型的函数来说,如果它的实现对x
、y
和z
有任何有意义的作用,那将是灾难性的。 如果你想实现它,它需要一个本身以正确的方式是可变参数的函数:
const reallyOkay: TasLastArg<string> = (...args: [...initArgs: any[], lastArg: string]) => {
console.log((args[args.length - 1] as string).toUpperCase());
}
reallyOkay("shouldWork"); // SHOULDWORK
reallyOkay(1, 2, 3, 4, 5, 6, 7, true, new Date(), "shouldAlsoWork"); // SHOULDALSOWORK
不,至少在最初看来,args[args.length-1]
不会被自动解释为string
。
操场链接到代码