typescript - Typinträffning för interface


Jag har följande typer:

interface A { a: string }
interface B extends A { b: string }
interface C extends A { c: string }

Jag vill nu skriva följande funktion som returnerar en A:

function test(t: number): A {
    return t > 10
        ? { a: "a", b: "b" }
        : { a: "a", c: "c" };
}

Detta fungerar bara om jag uttryckligen kastar de returnerade objekten till A, B eller C, eller om jag skapar separata funktioner som uttryckligen returnerar antingen en B eller en C och använder dessa för att konstruera objektet.

Finns det något sätt för kompilatorn att härleda att det returnerade objektet faktiskt är en B eller en C och därför också en A, utan att jag behöver specificera det?

Svar #1

Min förståelse är att det beror på att TypeScript tillämpar ytterligare begränsningar på objektlitteraler när det gäller överflödiga egenskaper. Om det skrivs om på detta sätt finns det inget fel:

interface A { a: string }
interface B extends A { b: string }

function test(): A {
    const result = { a: "a", b: "b" };
    return result;
}

Det finns också kompilatoralternativet suppressExcessPropertyErrors.

Svar #2

Det verkar som att TypeScript inte härleder typen av ett objekt till den som definieras av ett interface.

Den härledda typen av { a: "a", b: "b" } är { a: string, b: string }, som kan användas där en A eller en B kan användas, men det är varken A eller B, det är en annan typ.

Så svaret är: nej, kompilatorn kommer inte att härleda A eller B, den kommer att härleda något annat, och en typomvandling är nödvändig om den önskade typen är A eller B.