yah*_*wai 4 parameters tuples typescript
我想替换函数中最后一个参数的类型,同时保留所有函数参数的名称。就我而言,最后一个参数也是可选的。
例如:
type OrigArg = { arg: number };
type ReplacedArg = { arg: string };
type OrigFunc = (a: number, b: string, c?: OrigArg) => string
type ReplaceLast<TFunc, TReplace> = // type I'm looking for
type ReplacedFunc = ReplaceLast<OrigFunc, ReplacedArg>
// type ReplacedFunc = (a: number, b: string, c?: ReplacedArg) => string
Run Code Online (Sandbox Code Playgroud)
更复杂的是前面的参数的数量和类型是可变的,我只知道最后一个参数将是某种类型,我想用自定义的类型替换它。
好吧,这有点困难,我将解释一下。往下看TL;DR。
仅在传播原始参数时才保留打字稿中的参数名称,例如:
type OrigParams = Parameters<OrigFunc>;
type AnotherFunc = (...args: OrigParams) => any;
Run Code Online (Sandbox Code Playgroud)
这是由于 TS 的本质,其中Parameters元组确实是一个特殊的元组,它将名称保留为内部的、不可访问的元数据,在更改元组或创建另一个元组时,这些元数据会被破坏。IE:
type F = (a: any, b: any) => void;
type P1 = Parameters<F>;
type P2 = [any, any];
Run Code Online (Sandbox Code Playgroud)
即使结构相同,这里P1和也是不同的类型。P2
引用 TS:
请注意,当从参数序列推断出元组类型并随后将其扩展为参数列表时(如 U 的情况),原始参数名称将在扩展中使用(但是,这些名称没有语义含义,否则不会可观察)。
但是,这可以通过使用参数元组上的映射类型来完成,因为映射元组保留了参数名称,并且在考虑到“最后”项问题的情况下进行了一些后处理。
type ReplaceLastParam<TParams extends readonly any[], TReplace> = {
[K in keyof TParams]: // We should put the replace code here
}
Run Code Online (Sandbox Code Playgroud)
K是一个stringwhile 映射类型,即keyof TParams具有"0" | "1" | "2"三个元素的元组的情况。因此,在只有三个参数的情况下,我们可以轻松编写:type ReplaceParam2<TParams extends readonly any[], TReplace> = {
[K in keyof TParams]: K extends "2" ? TReplace : TParams[K]
}
Run Code Online (Sandbox Code Playgroud)
type LastIndex<T extends readonly any[]> =
((...t: T) => void) extends ((x: any, ...r: infer R) => void) ? Exclude<keyof T, keyof R> : never;
Run Code Online (Sandbox Code Playgroud)
这种类型计算一个元组的键R,该元组的元素比元组少一个T,并用 来区分它们Exclude:所以Exclude<"0" | 1" | "2", "0" | "1">正是"2"我们的最后一项。请注意,我们在这里使用类型推断和函数剩余推断。
ReplaceLast) 来包装我们刚刚创建的参数更改类型:长话短说:
// Index helper
type LastIndex<T extends readonly any[]> =
((...t: T) => void) extends ((x: any, ...r: infer R) => void) ? Exclude<keyof T, keyof R> : never;
// Replace last parameter with mapped type
type ReplaceLastParam<TParams extends readonly any[], TReplace> = {
[K in keyof TParams]: K extends LastIndex<TParams> ? TReplace : TParams[K]
}
// Replace function
type ReplaceLast<F, TReplace> = F extends (...args: infer T) => infer R
? (...args: ReplaceLastParam<T, TReplace>) => R
: never;
Run Code Online (Sandbox Code Playgroud)
这很有趣!希望这能回答您的问题,但是如果您在应用程序中确实需要这个,我希望您知道自己在做什么,因为该要求可能可以以更简单的方式解决。
| 归档时间: |
|
| 查看次数: |
1990 次 |
| 最近记录: |