Website-Suche

typescript - Wie implementiert man "Wenn kein Interface, füge die notwendigen Eigenschaften hinzu, um übereinzustimmen"?


Ich hatte Schwierigkeiten mit dem Titel, aber das Codebeispiel ist sehr unkompliziert:

// Setup
interface Dog {
    name: string;
}

interface Dachshund extends Dog {
    length: number;
}

function isDachshund (dog: Dog): dog is Dachshund {
    return (dog as Dachshund).length !== undefined;
}

// Problem
// We have an object that could match two different interfaces
let unknownDog: Dog | Dachshund = { name: "Rufus" };

// If it's not this specific interface, add the missing property
if (!isDachshund(unknownDog)) {
    (unknownDog as Dachshund).length = 5;
}

unknownDog // compiler still thinks Dog | Dachshund, but we know for certain it's a Dachshund at this point

Ist es möglich, den TypeScript-Compiler dazu zu bringen, zu erkennen, dass wir die notwendigen Eigenschaften hinzugefügt haben, um den Vereinigungstyp einzugrenzen? Gibt es eine andere Möglichkeit, meine Typen zu strukturieren, um dieses Problem zu vermeiden?

Antwort #1

Interessante Frage.

Soweit ich sehen kann (und bitte korrigiere mich jemand, wenn ich falsch liege), sieht es so aus, als würde TypeScript einfach nicht unterstützen, was du hier speziell zu tun versuchst.

Siehe dieses GitHub-Problem: https://github.com/microsoft/TypeScript/issues/27568

Im Wesentlichen versuchen Sie, TypeScript bewusst zu machen, welche Änderungen Sie an einem Objekt eines breiteren Typs vorgenommen haben, und korrekt den engeren Typ abzuleiten.

Das oben erwähnte Github-Problem scheint zu suggerieren: ‚Nein, zu schwer‘.

Beachten Sie, dass TypeScript Änderungen dieser Art nicht verfolgt, wenn keine Typannotationen verwendet werden!

const rufus = {
    name: "foo"
}; 


rufus.length = 9; //Property 'length' does not exist on type '{ name: string; }'.(2339)

Was ich hier tun würde, ist einfach, das Objekt nicht zu verändern, sondern stattdessen einfach neue Objekte zu deklarieren:

function usesADog(unknownDog: Dog | Dachshund){

    const dogToUse = isDachshund(unknownDog) ? unknownDog: {...unknownDog, length: 5}; 

    dogToUse; //const dogToUse: Dachshund

}

Spielplatz

Antwort #2

Typescript weiß, dass der Typ von unknownDog Dachshund ist, nur in einem Block, der durch einen Aufruf der Funktion isDachshund geschützt ist. Denn der Rückgabewert der Funktion ist dog is Dachshund (Typ-Prädikat).

if (!isDachshund(unknownDog)) {
    ... //here the type of unknownDog is Dog.  
}

else {
   ... // and here the type is Dachshund
}

// but here again the type is Dog|Dachshund

Also, im if-Block können Sie die Codes schreiben, die ausgeführt werden sollen, wenn der Typ von unknownDog Dog ist.
Im else-Block die Codes, die ausgeführt werden sollen, wenn der Typ von unknownDog Dachshund ist.