Avancerade TypeScript-argumentbegränsningar


Jag undrar om något som följer är möjligt i TypeScript, vad jag försöker uppnå:

  1. Om type är inbox ska obj vara av typen interface IInbox.
  2. Om type är sent då bör obj vara av typen gränssnitt ISent.
interface IInbox {

}

interface ISent {

}

class MailClient {
    delete(type: "inbox" | "sent", obj: IInbox | ISent) {

    }
}

let client = new MailClient();
client.delete('inbox', <ISent>{}); // should give compile error

Svar #1

Du kan definiera flera signaturer:

class MailClient {
    delete(type: "inbox", obj: IInbox);
    delete(type: "sent", obj: ISent)
    delete(type: "inbox" | "sent", obj: IInbox | ISent) {}
}

Men det kommer fortfarande inte att ge ett kompilationsfel eftersom dina gränssnitt är identiska.
Eftersom TypeScript använder duck typing så uppfyller det tomma objektet ({}) typkraven.
Om du skiljer mellan de två:

interface IInbox {
    a: string;
}

interface ISent {
    b: string;
}

Då får du ditt fel:

client.delete('inbox', {} as ISent); // Argument of type '"inbox"' is not assignable to parameter of type '"sent"'

(kod i lekplats)

Svar #2

Såvitt jag vet är denna begränsning inte möjlig, ändå kan du enkelt skriva en mycket enkel lösning som följer:

class MailClient {
    delete(type: "inbox" | "sent", objI?: IInbox, objS?: ISent) {
        if ((type === "inbox" && typeof objS !== "undefined") ||
                 type === "send" && typeof objI !== "undefined") {
            throw new "Invalid parameter";    
        }
        let obj = (type === "inbox") ? objI : objS;
    }
}

Detta skulle göra ditt jobb på ett ganska läsbart sätt.