TypeScript: Kan jag ange en typalias för en överlagrad funktionssignatur?


Är det möjligt att skapa en typalias för en överlagrad funktionssignatur?

Till exempel har jag en funktion som:

function whenChanged(scope: ng.IScope, fn: ()=>void): ()=>void;
function whenChanged(fn: ()=>void, truthy:any): ()=>void;
function whenChanged(a,b): ()=>void {
    //...
}

Jag skulle vilja skapa en typalias för den överlagrade signaturen för att undvika upprepning och använda den på andra ställen där jag behöver beskriva typen av denna funktion.

Jag försökte:

type WC1 = (scope: ng.IScope, fn: ()=>void) => ()=>void;
type WC2 = (fn: ()=>void, truthy:any) => ()=>void;
type WhenChanged = WC1 | WC2;

const whenChanged: WhenChanged = (a,b) => {
    //...
};

Men när jag försöker använda denna funktion får jag ett felmeddelande i stil med "Kan inte anropa ett uttryck vars typ saknar en anropssignatur".

Jag kan på rak arm inte se något i dokumenten om typaliasing av funktionsöverlagringar.

Svar #1

Eftersom du redan har funktionen whenChanged:

function whenChanged(scope: ng.IScope, fn: ()=>void): ()=>void;
function whenChanged(fn: ()=>void, truthy:any): ()=>void;
function whenChanged(a,b): ()=>void {
    //...
}

Det enklaste sättet att få en typalias för dess typ är att använda en typeof-typfråga:

type WhenChanged = typeof whenChanged;

Det nästa, mest okomplicerade sättet att skapa typaliaset är att använda en överlagrad funktionssignatur (vilket är vad du letade efter):

type WhenChanged = {
  (scope: ng.IScope, fn: () => void): () => void;
  (fn: () => void, truthy: any): () => void;
}

(vilket är vad du kommer att se i snabbinfo om du hovrar över typeof-definitionen i din editor.) Observera att du inte behöver använda ett interface om du inte vill.

Nästa sak du skulle kunna göra är liknande det du gjorde, men problemet är att en överbelastning är en snitt, inte en union. Det är båda signaturerna:

type WC1 = (scope: ng.IScope, fn: ()=>void) => ()=>void;
type WC2 = (fn: ()=>void, truthy:any) => ()=>void;
type WhenChanged = WC1 & WC2; // and, not or

Var försiktig så att snitt av funktionssignaturer inte är kommutativa, särskilt eftersom de representerar överlagringar. Det betyder att följande typ tekniskt sett inte är densamma:

type NotWhenChanged = WC2 & WC1; // different type

eftersom överbelastningsupplösningen skulle äga rum i en annan ordning.

Observera att du inte kan anropa en funktion av typen WC1 | WC2 eftersom anropssignaturerna är olika och kompilatorn kan inte avgöra om funktionen är WC1 eller WC2.

Okej, där har du det. Hoppas det hjälper; lycka till!

Svar #2

Efter lite lekande visar det sig att svaret (åtminstone till viss del) är att använda ett gränssnitt. Detta verkar fungera:

interface WhenChanged {
    (scope: ng.IScope, fn: ()=>void): ()=>void
    (fn: ()=>void, truthy:any): ()=>void
}

const whenChanged: WhenChanged = (a,b) => {
    //...
};

Relaterade artiklar