Typescript generisk typ T toString


Jag tror inte att det är möjligt men det är värt att fråga. I en generell metod eller klass skulle jag vilja logga namnet på den generiska T-typen som har använts, jag behöver den som en sträng.

Föreställ dig en metod som denna:

static getTypeName<T>(): string {
    return typeof T; // This is wrong
}

Jag skulle förvänta mig att kunna använda det på det här sättet:

let m = getTypeName<Message>(); // Expected string "Message"
let p = getTypeName<Person>();  // Expected string "Person"

Ovanstående getTypeName är fel, det kommer inte ens att kompileras. typeof skulle transpileras i JS och skulle inte ge önskad effekt. Jag försökte olika saker men utan framgång.

Finns det något sätt att faktiskt göra det?

REDIGERA: Varför detta inte är en dubblett av: den här frågan

Frågan och exempel koden visar hur man får tillbaka ett objekt och inte namnet på den specificerade typen. Dessutom är metoden inte generisk eftersom om du försöker skicka in en Typ som har konstruktörsparametrar så visas felet: "[ts] Argument of type 'typeof MyType' is not assignable to parameter of type 'new() => MyType'." Dessutom, om du använder funktionen inom en generisk metod kan du inte använda T som parameter, vilket innebär att överallt där jag skulle behöva få namnet från den generiska typen, skulle jag behöva lägga till konstruktören i parametrarna.

Svar #1

Tja, Generics i TypeScript är bara en konstruktion som hjälper vid typkontroll. "T" är faktiskt "ingenting" - det är ingenting som kan transpileras till JavaScript. Men du behöver den här konstruktorns grej för att få ditt typsnamn. Det är därför du får det felmeddelandet. Du angav bara en typ men det som krävs är ett värde (som har den konstruktorns grejen) för att få din kod att fungera.

Redigera:

Det du behöver göra i vilket fall som helst är att tillhandahålla ett JavaScript-objekt. Något liknande detta skulle fungera:

class Foo<T> {
    test: T;

    constructor(value: T) {
        this.test = value;
    }

    getTypeNameOfTest(): string {
        return this.test.constructor.name;
    }
}

const foo = new Foo<Date>(new Date());
foo.getTypeNameOfTest();                // => "Date"

const baa = new Foo<string>("Howdy");
baa.getTypeNameOfTest();                // => "string"

Men här tillhandahåller du ett riktigt JavaScript-objekt istället för bara ett TypeScript-typnamn. Det är därför detta fungerar.

Svar #2

Efter att ha sökt igenom hela internet, skapat min egen dekoratör och pillat mycket med Typescript, snubblade jag över detta inlägg:

Hämta ett objekts klassnamn vid körning

I princip kan du använda Message.name så länge Message är en klass.

Var försiktig, eftersom om klassnamn minifieras vid en produktionsbyggnad kan detta sluta fungera, så kontrollera innan du använder denna metod.

Relaterade artiklar