typescript - Hur typer man korrekt parametrar på en generisk funktion?
Jag försöker tilldela en funktions parametrar till ett typalias. T.ex. för denna funktion:
function foo<T>(bar: T, baz: number) {}
Jag vill få signaturen för dess parametrar. Vanligtvis skulle jag göra så här:
type FooParams = Parameters<typeof foo>;
men problemet är att det resulterar i en signatur på [{}, number] vilket är logiskt eftersom jag inte har specificerat vad T är. Däremot skulle jag förvänta mig att detta fungerar:
type FooParams<T> = Parameters<typeof foo<T>>; // hopefully [T, number]
men det gör det inte, det resulterar bara i en massa syntaxfel.
Är det möjligt att korrekt få typen av en generisk funktions parameterlista?
Svar #1
Du kan använda för det infer-nyckelordet:
type Args<T> = T extends (...args: infer I) => any ? I : never;
type R = Args<(args: number, arg: string) => number >;
// R = [number, string]
Det betyder att typ I behandlas som generisk, men du behöver inte deklarera det som: let fn=<T>(arg:T): T {...
lekplats, dokument
Du kan använda generiska typer men du måste deklarera typen på funktionen:
type Foo<T> = (bar: T, baz: number) => void;
type R2<Placeholder> = Args<Foo<Placeholder>>; // [Placeholder, number]
type R3 = R2<boolean> // [boolean, number]
Svar #2
Min lösning är bara en tillfällig lösning som kan hjälpa. Detta är inte exakt vad du vill ha
Här har du en icke-generisk lösning. Jag menar att den bara fungerar med foo typ signatur
function foo<T>(bar: T, baz: number) { }
type Fn = (...args: any) => any
type Tail<T extends any[]> = T extends [infer _, ...infer Rest] ? Rest : never
type ReplaceFirstParameter<F extends Fn, Fst> =
(fst: Fst, ...args: Tail<Parameters<F>>) => ReturnType<F>
type Foo<T> = ReplaceFirstParameter<typeof foo, T>
type Result = ReplaceFirstParameter<typeof foo, number> // (fst: number, baz: number) => void
Denna lösning är mer generisk. Den kommer att ersätta alla unknown-parametrar med den angivna generiska argumentet.
Jag antar att varje funktion generisk är okänd - detta är den svaga punkten.
type MapPredicate<T, V> = T extends unknown ? V : T
type ReplaceUnknown<
Arr extends Array<unknown>,
Value,
Result extends Array<unknown> = []
> = Arr extends []
? []
: Arr extends [infer H]
? [...Result, MapPredicate<H, Value>]
: Arr extends [infer Head, ...infer Tail]
? ReplaceUnknown<[...Tail], Value, [...Result, MapPredicate<Head, Value>]>
: Readonly<Result>;
function foo<T>(bar: T, baz: number) { }
type Fn = (...args: any) => any
type ReplaceParameters<F extends Fn, Value> =
(...args: ReplaceUnknown<Parameters<F>, Value>) => ReturnType<F>
type Result = ReplaceParameters<typeof foo, number> // (fst: number, baz: number) => void
Lekplats
