Prienikové typy vs rozhrania v TypeScripte


Tu je scenár:

type Admin = {
    name : string,
    privileges : string[]
}
type Employee ={
    name : string,
    startDate : Date
}

type ElevatedEmployee = Admin & Employee;

const el : ElevatedEmployee ={ // all the properties must be implemented here else compiler will complain
    name : 'Max',
    privileges :['create server'],
    startDate : new Date()
}

Môžem dosiahnuť to isté pomocou rozhraní:

interface Admin {
    name : string,
    privileges : string[]
}

interface Employee {
     name : string,
    startDate : Date
}

interface Combined extends Admin, Employee { 
//this doesn't throw me a compilation error, even though i dont implement those properties here
}

Aký je rozdiel medzi prienikovými typmi a rozhraniami? Kedy použiť ktorý?

Odpoveď č. 1

1. Výkon Podľa wiki o výkone TypeScriptu:

Rozhrania vytvárajú jeden plochý typ objektu, ktorý detekuje konflikty vlastností, ktoré je zvyčajne dôležité vyriešiť! Na druhej strane, prieniky len rekurzívne spájajú vlastnosti a v niektorých prípadoch produkujú never. Rozhrania sa tiež zobrazujú konzistentne lepšie, zatiaľ čo typové aliasy na prieniky sa nedajú zobraziť v časti iných prienikov. Vzťahy medzi typmi rozhraní sa tiež ukladajú do vyrovnávacej pamäte, na rozdiel od prienikových typov ako celku. Posledný pozoruhodný rozdiel je, že pri kontrole voči cieľovému prienikovému typu sa každý člen kontroluje pred kontrolou voči „efektívnemu“/„zploštenému“ typu.

Z tohto dôvodu sa odporúča rozširovať typy pomocou rozhraní/interfaces/extends namiesto vytvárania priesečníkov typov.

Preto, ak sa obávate o výkon TS, zvážte používanie rozhraní.

2. Zložitý rozdiel medzi rozhraniami a typmi

typy sú indexované podľa predvoleného, zatiaľ čo rozhrania nie sú. To robí rozhrania bezpečnejšími. Pozrite sa na tento príklad:

type Admin = {
    name: string,
    privileges: string[]
}

type Employee = {
    name: string,
    startDate: Date
}

type CombinedType = Admin & Employee;

interface CombinedInterface extends Admin, Employee { }

const interfaceData: CombinedInterface = { name: '', privileges: [], startDate: new Date() }
const typeData: CombinedType = { name: '', privileges: [], startDate: new Date() }


const handleType = (obj: Record<string, unknown>) => {
    obj['name'] = 42 // unsafe
}


handleType(interfaceData) // error
handleType(typeData) // ok


Pozrite si túto odpoveď a môj článok pre viac kontextu.

Ako ste si možno všimli, handleType očakáva takmer akýkoľvek objekt a dokáže ho modifikovať/mutovať nebezpečným spôsobom. Avšak, ak máte objekt s interface, nemôžete ho ani predložiť nebezpečnej funkcii.

P.S. Existuje jemný rozdiel medzi typmi a rozhraniami z hľadiska vyhodnocovania, pozri tu, ale vo vašom príklade to nie je prípad

Súvisiace články