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