TypeScript-interface versus type: echte verschillen, getest met de compiler

  1. Home
  2. Blog
  3. Softwareontwikkeling

Softwareontwikkeling

TypeScript-interface versus type: Echte verschillen, getest met de compiler

Interfaces en typealiassen overlappen elkaar zozeer dat de keuze vaak willekeurig aanvoelt. Dit is wat de een kan doen en de ander niet, bevestigd door echte compilerfouten, plus een eenvoudige regel die uw team kan volgen.

8 min leestijd
TypeScript-interface versus type: echte verschillen, getest met de compiler

Belangrijkste punten

  • Voor gewone objectvormen zijn een interface en een typealias vrijwel uitwisselbaar.
  • Alleen type kan unies, tupels en andere niet-objecttypen benoemen.
  • Alleen interface ondersteunt het samenvoegen van declaraties, waarbij twee declaraties worden gecombineerd.
  • Een algemene regel: interfaces voor objectvormen type voor al het andere, consistent toegepast.

Weinig TypeScript-vragen veroorzaken zoveel discussie als TypeScript-interface versus type. Veel artikelen vermelden verschillen die er in oudere versies toe deden, maar nu verouderd zijn. Dus in plaats van beweringen te herhalen, hebben we ze getest.

We hebben één bestand geschreven waarin we elk verschil hebben gecontroleerd, en dit hebben we gecontroleerd met TypeScript 5.6.3 in de strikte modus. De hieronder genoemde compilerfouten zijn afkomstig van die run. Gedrag kan tussen versies veranderen, dus controleer het met de TypeScript-versie die uw project gebruikt. Als je nieuw bent in de taal, begin dan met onze TypeScript-tutorial voor beginners.

Het korte antwoord

Een interface beschrijft de vorm van een object en kan worden uitgebreid of heropend. Een type alias geeft een naam aan elk type, inclusief objecten, unies, tupels en functietypen. Waar beide kunnen werken, zit het verschil vooral in stijl.

Waar ze hetzelfde zijn

Deze twee verklaringen beschrijven identieke vormen:

interface User {
  id: number;
  name: string;
  email?: string;
}

type UserAlias = {
  id: number;
  name: string;
  email?: string;
};

const a: User = { id: 1, name: "Asha" };
const b: UserAlias = a;   // no error

TypeScript gebruikt structureel typen, wat betekent dat het vormen vergelijkt in plaats van namen. Daarom kan een User zonder klachten aan een UserAlias worden toegewezen. Beide ondersteunen optionele eigenschappen, readonly eigenschappen, methoden en indexhandtekeningen.

Interface versus type naast elkaar

Functie interface typ
Objectvormen Ja Ja
Vakbonden, zoals "a" | "b" Nee Ja
Tupels en primitieven Nee Ja
Toegewezen en voorwaardelijke typen Nee Ja
Verklaring samenvoegen Ja Nee, het is een fout
Verlengen strekt zich uit & kruispunt
Conflicterende eigenschappen Fout bij de aangifte Kan stilletjes never worden
Gebruikt met implements Ja Ja, als het een objecttype is

Wat alleen typen kan doen

Veel nuttige typen zijn helemaal geen objectvormen, en alleen een typealias kan ze een naam geven:

type Status = "pending" | "paid" | "shipped";   // union
type Point = [number, number];                    // tuple
type Handler = (event: string) => void;           // function type
type Keys = keyof User;                           // computed type
type ReadonlyUser = Readonly<User>;               // utility type

Union-typen behoren tot de meest waardevolle functies van TypeScript, omdat de compiler vervolgens elke waarde buiten de lijst afwijst:

let s: Status = "paid";
s = "refunded";

// error TS2322: Type '"refunded"' is not assignable to type 'Status'.

Hiermee worden typefouten en verouderde waarden opgespoord tijdens het compileren, voordat ze in productie gaan.

Verklaring samenvoegen

Als u een interface met dezelfde naam tweemaal declareert, voegt TypeScript deze samen tot één interface:

interface Settings {
  theme: string;
}
interface Settings {
  language: string;
}

const settings: Settings = { theme: "dark", language: "en" };   // no error

Probeer hetzelfde met een typealias, en de compiler weigert:

type Config = { theme: string };
type Config = { language: string };

// error TS2300: Duplicate identifier 'Config'.

Door samen te voegen kunt u met bibliotheken hun typen uitbreiden. U kunt bijvoorbeeld een aangepaste eigenschap toevoegen aan de globale Window-interface of aan het aanvraagobject van een raamwerk, zonder de bibliotheek te wijzigen. Dat is echt nuttig.

De keerzijde is dat fusies per ongeluk kunnen gebeuren. Als twee bestanden in een project een interface met dezelfde naam in hetzelfde bereik declareren, worden ze stilzwijgend gecombineerd, wat verwarrend kan zijn. Een typealias maakt van die botsing een fout.

verlengt versus kruispunten

Met beide kun je voortbouwen op een bestaand type:

interface Admin extends User {
  permissions: string[];
}

type AdminAlias = UserAlias & { permissions: string[] };

Voor compatibele eigenschappen is het resultaat hetzelfde. Het verschil komt tot uiting in een conflict. Wanneer een interface het type van een eigenschap op incompatibele wijze probeert te wijzigen, rapporteert de compiler dit onmiddellijk:

interface Base { id: number }
interface Broken extends Base { id: string }

// error TS2430: Interface 'Broken' incorrectly extends interface 'Base'.
//   Types of property 'id' are incompatible.
//     Type 'string' is not assignable to type 'number'.

Een kruispunt klaagt niet wanneer het wordt aangegeven. In plaats daarvan wordt de conflicterende eigenschap never, een type dat geen enkele waarde kan hebben. De fout verschijnt pas later, wanneer u deze probeert te gebruiken:

type Mixed = { id: number } & { id: string };
const m: Mixed = { id: 1 };

// error TS2322: Type 'number' is not assignable to type 'never'.

Die latere fout is nog verwarrender, omdat deze wegwijst van de feitelijke fout. Dit is een praktische reden om de voorkeur te geven aan extends bij het opbouwen van objecttypen.

Klassen en werktuigen

Een klasse kan beloven een vorm te matchen met behulp van implements, en dit werkt met een interface of een objecttype-alias:

class Account implements User {
  constructor(public id: number, public name: string) {}
}

Deze is zonder fouten samengesteld. Merk op dat implements alleen controleert of de klasse overeenkomt. Er worden geen eigenschappen of code toegevoegd. Een klasse kan geen unietype implementeren, omdat er geen enkele vorm is die daarbij past.

Alleen-lezen en hulpprogrammatypen

Hulpprogrammatypen zoals Readonly, Partial, Pick en Omit werken met zowel interfaces als aliassen. Het resultaat is een nieuw type, dat doorgaans wordt benoemd met een typealias:

const r: ReadonlyUser = { id: 3, name: "Dev" };
r.name = "Chitra";

// error TS2540: Cannot assign to 'name' because it is a read-only property.

Houd er rekening mee dat readonly alleen een controle tijdens het compileren is. Tijdens runtime is het object gewoon JavaScript en kan het nog steeds worden gewijzigd door code die de typen omzeilt.

Tip: Typen verdwijnen wanneer TypeScript naar JavaScript compileert. Gegevens die van buitenaf binnenkomen, zoals een API-antwoord, worden tijdens runtime niet gecontroleerd alleen omdat ze een type hebben. Valideer het bijvoorbeeld met een schemabibliotheek. In onze API-tutorial voor ophalen wordt uitgelegd hoe u veilig met API-reacties omgaat.

Compilerprestaties

De eigen prestatierichtlijnen van het TypeScript-team suggereren dat de voorkeur wordt gegeven aan interfaces die extends gebruiken boven grote kruispunten, omdat de compiler interfacerelaties efficiënter in de cache kan opslaan. Bij kleine en middelgrote projecten is het onwaarschijnlijk dat u enig verschil merkt. Het kan ertoe doen in zeer grote codebases met diep samengestelde typen. Wij hebben dit zelf niet gemeten.

Welke moet je gebruiken?

Een veelgebruikte regel, in lijn met de richtlijnen van het TypeScript-handboek, is:

  • Gebruik interface voor objectvormen, vooral openbare API’s en alles wat klassen implementeren of door anderen kunnen worden uitgebreid.
  • Gebruik type voor verbindingen, tupels, functietypen en toegewezen of berekende typen.
Jij definieert Gebruik
Een gegevensmodel, zoals Gebruiker of Bestelling interface
Een reeks toegestane waarden type unie
Een paar met vaste lengte of een triple type tupel
Een terugbelhandtekening typ
Uitbreiding van de typen van een bibliotheek interface, door samenvoeging
Een variatie op een bestaand type type met een nutstype

Sommige teams gebruiken type gewoon overal, en dat werkt ook prima. Het belangrijkste is consistentie, dus kies een conventie, schrijf deze in je stijlgids en laat een linter deze afdwingen. ESLint’s consistent-type-definitions regel van typescript-eslint kan dit doen.

Veel voorkomende fouten

  • Eindeloze discussies. Beide zijn prima voor objecten, dus bepaal de regel één keer en ga verder.
  • Per ongeluk samenvoegen. Door een interfacenaam binnen hetzelfde bereik opnieuw te gebruiken, worden deze op de achtergrond gecombineerd.
  • Conflicterende kruispunten. Ze creëren never typen met later verwarrende fouten.
  • Vertrouwde typen tijdens runtime. Ze worden gewist, dus valideer externe gegevens.
  • Gebruik any om fouten uit te sluiten. De controle wordt uitgeschakeld. Geef de voorkeur aan unknown en beperk het.

Ertussen schakelen in een bestaande codebase

Het veranderen van een interface in een type, of omgekeerd, is meestal veilig voor gewone objectvormen, omdat TypeScript typen vergelijkt op basis van hun structuur, niet op basis van hun naam. Er zijn nog een aantal zaken die je moet controleren voordat je overstapt:

  • Door een interface naar een typealias te converteren, wordt het samenvoegen van declaraties verwijderd, zodat elke tweede declaratie met dezelfde naam een dubbele identificatiefout wordt.
  • Het converteren van een typealias naar een interface werkt alleen voor objectvormen. Vakbonden, tupels en toegewezen typen moeten als typealiassen blijven.
  • Foutmeldingen en hovers van de editor kunnen het type anders weergeven, wat teamgenoten kan verrassen maar het gedrag niet verandert.

Voer de wijziging door in één gerichte pull-request, voer de compiler uit in de strikte modus en uw testpakket, en vermijd het vermengen ervan met functiewerk, zodat reviewers kunnen zien dat er verder niets is veranderd.

Tot slot

De interface versus type-vraag heeft een rustig antwoord: ze overlappen elkaar voor objecten, elk heeft een paar unieke vaardigheden, en consistentie is belangrijker dan de keuze. Gebruik interfaces voor vormen en typen voor al het andere, tenzij uw team anders verkiest. Om zelf de verschillen te zien, kopieert u de bovenstaande voorbeelden naar een bestand en voert u daarop tsc --noEmit --strict uit.

Veelgestelde vragen

Wat is het verschil tussen interface en type in TypeScript?

Beide kunnen objectvormen beschrijven. Alleen het type kan unies, tupels en berekende typen een naam geven, terwijl alleen de interface het samenvoegen van declaraties ondersteunt.

Moet ik interface of type gebruiken voor React-rekwisieten?

Beide werken goed. Veel teams gebruiken interfaces voor rekwisieten, terwijl anderen de voorkeur geven aan type vanwege consistentie met vakbonden. Kies er één en pas deze gedurende het hele project toe.

Kan een type een interface uitbreiden?

Ja, door een kruispunt te gebruiken zoals type Admin = Gebruiker & { permissies: string[] }. Een interface kan ook een objecttype-alias uitbreiden.

Is de interface sneller dan het type?

De prestatierichtlijnen van TypeScript geven de voorkeur aan een interface die zich uitstrekt over grote kruispunten in grote codebases. Bij typische projecten is het onwaarschijnlijk dat het verschil merkbaar is.

Wat is het samenvoegen van aangiften?

Het is wanneer twee interfaces met dezelfde naam in hetzelfde bereik worden gecombineerd tot één. Type-aliassen kunnen niet worden samengevoegd en dubbele namen veroorzaken een fout.

Blijf leren

Werk met Stack Quora

Hulp nodig met testen, WordPress of SEO?

We helpen teams betere software te leveren en hun sites te laten groeien. Vertel ons waar u mee bezig bent en wij stellen een duidelijke volgende stap voor.

Blijf lezen

Meer handleidingen over testen, AI en moderne ontwikkeling

Genoten van dit artikel? Kies een onderwerp en ga direct naar onze nieuwste tutorials.

Kunstmatige intelligentie

AI-hallucinaties uitgelegd: waarom taalmodellen dingen verzinnen en hoe ze te verminderen

AI-hallucinaties uitgelegd: wat ze zijn, waarom taalmodellen ze produceren, veelvoorkomende typen, hoe je ze kunt verminderen met aarding en aanwijz…

Lees artikel →
DevOps

Omgevingsvariabelen uitgelegd: .env-bestanden, geheimen en configuratie goed gedaan

Omgevingsvariabelen uitgelegd met Python-voorbeelden die we hebben uitgevoerd: ze lezen en instellen, waarom elke waarde een string is, .env-bestand…

Lees artikel →
Softwareontwikkeling

API-snelheidsbeperking uitgelegd: algoritmen, headers en afhandeling van 429-fouten

API-snelheidsbeperking uitgelegd met een simulatie die we hebben uitgevoerd: token-bucket, vast venster, schuifvenster, 429 reacties, headers van sn…

Lees artikel →
Testautomatisering

Spotten in Python: unittest.mock, patch en de fouten die tests doen liegen

Spotten in Python met unittest.mock, getest: Mock en return_value, side_effect, patchen waar een naam wordt gebruikt, spec en autospec, spotdatums e…

Lees artikel →
Softwaretesten

Codedekking uitgelegd: lijn versus filiaaldekking en wat 100% werkelijk betekent

Codedekking uitgelegd met een echte dekking.py-run: dekking van lijnen, vertakkingen en condities, een rapport lezen, waarom 100% dekking nog steeds…

Lees artikel →
Databases & SQL

DELETE versus TRUNCATE versus DROP in SQL: verschillen, terugdraaien en wanneer elk te gebruiken

DELETE versus TRUNCATE versus DROP uitgelegd met geteste SQL: wat elk verwijdert, terugdraaien, triggers, identiteitsreset, snelheid en hoe PostgreS…

Lees artikel →
Databases & SQL

SQL-weergaven uitgelegd: creëer, gebruik en vermijd de valkuilen, met voorbeelden

SQL-weergaven uitgelegd met query's die we hebben uitgevoerd: een weergave maken, live resultaten, kolommen verbergen, prestaties, bijwerkbare en ge…

Lees artikel →
Softwareontwikkeling

TypeScript-interface versus type: echte verschillen, getest met de compiler

TypeScript-interface versus type, gecontroleerd met de echte compiler: wat beide kunnen doen, wat slechts één kan doen, samenvoegen van declaraties,…

Lees artikel →
Softwareontwikkeling

Python *args en **kwargs uitgelegd: flexibele functies met duidelijke voorbeelden

Python *args en **kwargs uitgelegd met code die we hebben uitgevoerd: in- en uitpakken, parametervolgorde, argumenten die alleen trefwoorden en posi…

Lees artikel →
Softwareontwikkeling

Python Lambda-functies: syntaxis, echt gebruik en wanneer u ze niet moet gebruiken

Python lambda-functies uitgelegd met code die we hebben uitgevoerd: syntaxis, sorteren met sleutel, kaart en filter, sluitingen, de laat-bindende va…

Lees artikel →
Kunstmatige intelligentie

Wat zijn AI-agenten? Hoe ze werken, met een eenvoudige agentloop die u kunt uitvoeren

Wat zijn AI-agenten? Een duidelijke gids voor de agentenlus, tools, geheugen en vangrails, met een kleine Python-lus die we hebben uitgevoerd, echte…

Lees artikel →
DevOps

Monitoring versus waarneembaarheid: het echte verschil, met logboeken, statistieken en sporen

Monitoring versus waarneembaarheid uitgelegd: bekende en onbekende fouten, logboeken, statistieken en sporen, een walkthrough voor afrekenincidenten…

Lees artikel →
DevOps

Docker-volumes versus bindingsmounts: bewaar containergegevens op de juiste manier

Docker-volumes versus bind-mounts uitgelegd: waarom containergegevens verdwijnen, benoemde volumes, bind-mounts, tmpfs, Compose-voorbeelden, back-up…

Lees artikel →
Testautomatisering

TDD versus BDD: belangrijkste verschillen, één functie die op beide manieren is gebouwd en wanneer deze moet worden gebruikt

TDD versus BDD uitgelegd met één kortingsfunctie die in beide richtingen is gebouwd: rood-groen-refactor met code die we hebben uitgevoerd, gegeven-…

Lees artikel →
Softwareontwikkeling

Git merge vs rebase: verschillen, voorbeelden en wanneer je wat gebruikt

Git merge vs rebase uitgelegd met echte logoutput, een vergelijkingstabel, de gouden regel van rebase en een veilige teamwerkwijze.

Lees artikel →
Softwareontwikkeling

Python list comprehension: syntaxis, voorbeelden en wanneer je het vermijdt

Python list comprehension uitgelegd: syntaxis, filteren, if-else, geneste lussen, gemeten tijden en wanneer een gewone for-lus beter is.

Lees artikel →
Databases & SQL

SQL JOIN uitgelegd met voorbeelden (Inner, Left, Right, Full)

Begrijp SQL joins stap voor stap met voorbeeldtabellen en queries: INNER, LEFT, RIGHT, FULL, CROSS en SELF, plus veelgemaakte fouten en prestatietips.

Lees artikel →