Kan jag tvinga det sista argumentet av en funktion i TypeScript?


Låt oss säga att jag har ett funktions-typgränssnitt som jag vill använda för att upprätthålla en viss signatur för specifika funktioner.

Finns det ett sätt att tvinga att det sista argumentet i en funktion måste vara en viss typ?

Finns det ett sätt att göra något liknande detta:

interface SomeType { /*...*/ }

/**
 * this is the function type I want to enforce
 * I want the last argument of any `Modifcation` to be `SomeType`
 */
interface Modification {
    (...args: [...firstArgs: any[], lastArgument: SomeType]): void
}

// enforcing `Modification`
const someModification: Modification = (firstParam: string, second: number, third: SomeType) => {
    /*...*/
}

Jag vet att TypeScript använder spridningssyntaxen och tuple-typer, men pseudokoden ovan fungerar inte.

Finns det ett sätt att göra detta?

Redigera:

Ansvarsfriskrivning: Jag tror inte att det finns ett sätt att göra det jag vill och den här frågan kanske därför inte är helt konstruktiv.

Kontext:

Jag har ett antal klasser och jag vill införa en viss konvention på specifika metoder i dessa klasser. Jag kan säkerställa att en viss metod måste följa en funktionstyp genom att deklarera ett annat gränssnitt och säga att min klass implementerar det gränssnittet.

t.ex.

interface Convention {(arg0: string, arg1: number): Something}

interface MyClassMethodRequirements {
    myMethod: Convention,
    myOtherMethod: Convention
}

class MyClass implements MyClassMethodRequirements {
    myMethod(a: string, b: number) { return new Something(); }
    myOtherMethod(label: string, aNumber: number) { return new Something(); }
    otherMethod() { return 'just another non-conforming method' }
}

Vad jag vill uppnå:

Ovanstående Convention är bara ett exempel. Det jag vill upprätthålla är att en metod som påstås vara en Convention måste ha/ta hänsyn till båda parametrarna.

t.ex. (pseudo-kod)

interface NewConvention {(firstArg: any, lastArg?: RequiredType): Something}

interface MyClassMethodRequirements {
    myMethod: NewConvention,
    myOtherMethod: NewConvention
}

class MyClass implements MyClassMethodRequirements {
    myMethod(a: string, b?: RequiredType) { return new Something(); }
    // i want an error here because `myOtherMethod` doesn't list `lastArg: RequiredType` in it's parameters
    myOtherMethod(label: string) { return new Something(); }
    otherMethod() { return 'just another non-conforming method' }
}

För lite mer kontext, lastArg i NewConvention ska vara en valfri överskrivning.

Igen, jag tror inte att det jag försöker uppnå är möjligt, så detta kan vara okonstruktivt.

Tack för din hjälp :)

Svar #1

Om du känner till det maximala antalet parametrar kan du göra så många överlagringar som behövs.

type Modification =
    { (arg1: any, lastArgument: SomeType): void } |
    { (arg1: any, arg2: any, lastArgument: SomeType): void } |
    { (arg1: any, arg2: any, arg3: any, lastArgument: SomeType): void };

Svar #2

Du kan ha det första argumentet (av typen SomeType) som valfritt på följande sätt:

interface SomeType {
    a: number; // just so it's not an empty definition
}

type Modification =
    { (first: SomeType, ...rest: (string | number)[]): void; }
    | { (...rest: (string | number)[]): void; }

// fine
const someModification1: Modification = (firstParam: string, second: number) => {}
const someModification2: Modification = (third: SomeType, firstParam: string, second: number) => { }

// error
const someModification3: Modification = (firstParam: string, second: number, third: SomeType) => { }

Observera att om du använder any[] för argumenten så kommer det också att täcka SomeType-argumentet.

Relaterade artiklar