InstanceType în TypeScript

InstanceType<C> dă tipul obiectelor create cu new dintr-un tip de clasă C.

Sintaxă
type InstanceType<T extends abstract new (...args: any) => any> =
    T extends abstract new (...args: any) => infer R ? R : any;

Ce face InstanceType

InstanceType<typeof Elev> este tipul unui obiect creat cu new Elev(...), adică același lucru cu Elev. Pare inutil pentru o clasă cunoscută, dar devine necesar în cod generic, unde ai doar clasa ca valoare: o funcție care primește o clasă și returnează un obiect al ei.

Exemple: o fabrică creeaza(Clasa, ...args), un registru de servicii în care cheile sunt clase, mixin-uri. Se folosește împreună cu ConstructorParameters.

Tipul primit trebuie să fie un constructor (new (...) => ...), deci se scrie de obicei cu typeof.

Parametri

Parametru Descriere
T Tipul unei clase (constructor).

Ce returnează

Tipul obiectelor create de constructor.

Exemple

Exemplul 1: Fabrică generică

Funcția primește orice clasă și argumentele constructorului ei și returnează exact tipul obiectului.

function creeaza<C extends new (...args: never[]) => object>(
    Clasa: C,
    ...args: ConstructorParameters<C>
): InstanceType<C> {
    return new Clasa(...args) as InstanceType<C>;
}

class Elev {
    constructor(public nume: string) {}
}
class Curs {
    constructor(public materie: string, public ore: number) {}
}

const e = creeaza(Elev, "Ana");                 // Elev
const c = creeaza(Curs, "informatică", 4);       // Curs
console.log(e.nume, c.materie, c.ore);

Rezultat

Ana informatică 4

Exemplul 2: Registru de clase

class Email {
    trimite(text: string) { return `email: ${text}`; }
}
class Sms {
    trimite(text: string) { return `SMS: ${text.slice(0, 15)}`; }
}

const canale = { email: Email, sms: Sms };
type Canal = keyof typeof canale;

function canal<K extends Canal>(nume: K): InstanceType<(typeof canale)[K]> {
    return new canale[nume]() as InstanceType<(typeof canale)[K]>;
}

console.log(canal("email").trimite("Nota ta este 10"));
console.log(canal("sms").trimite("Ședința începe la ora 18"));

Rezultat

email: Nota ta este 10
SMS: Ședința începe

Exemplul 3: Tipul nu este un constructor

function f() {
    return 1;
}
type T = InstanceType<typeof f>;
const t: T = 1;
console.log(t);

Eroarea afișată de tsc

exemplu.mts(4,23): error TS2344: Type '() => number' does not satisfy the constraint 'abstract new (...args: any) => any'.
  Type '() => number' provides no match for the signature 'new (...args: any): any'.

Greșeli frecvente

  • Folosești InstanceType<typeof X> când poți scrie direct X. Rezervă-l pentru codul generic.

Comenzi înrudite

  • ConstructorParameters: ConstructorParameters<typeof Clasa> dă tipurile parametrilor constructorului clasei, ca tuple.
  • ReturnType: ReturnType<F> dă tipul rezultatului unei funcții; pentru o funcție concretă scrii ReturnType<typeof f>.
  • class: Clasele din JavaScript, cu tipuri pe câmpuri, constructor și metode, plus modificatori de acces și interfețe.
  • generics (<T>): Parametri de tip: o funcție sau clasă scrisă o dată, care funcționează cu orice tip și păstrează tipul exact.