TypeScript: interfacce vs tipi


Risposte:


574

Secondo le specifiche del linguaggio TypeScript :

A differenza di una dichiarazione di interfaccia, che introduce sempre un tipo di oggetto denominato, una dichiarazione di alias di tipo può introdurre un nome per qualsiasi tipo di tipo, inclusi i tipi di primitiva, unione e intersezione.

Le specifiche continuano a menzionare:

I tipi di interfaccia hanno molte somiglianze con i tipi di alias per i letterali del tipo di oggetto, ma poiché i tipi di interfaccia offrono più funzionalità, in genere si preferisce digitare gli alias. Ad esempio, il tipo di interfaccia

interface Point {
    x: number;
    y: number;
}

potrebbe essere scritto come alias del tipo

type Point = {
    x: number;
    y: number;
};

Tuttavia, ciò significa che si perdono le seguenti funzionalità:

  • Un'interfaccia può essere nominata in una clausola extends o implementa, ma un alias di tipo per un tipo di oggetto letterale non può più essere vero da TS 2.7.
  • Un'interfaccia può avere più dichiarazioni unite , ma un alias di tipo per un tipo di oggetto letterale non può.

109
Che cosa significano "dichiarazioni unite multiple" nella seconda differenza?
jrahhali,

66
@jrahhali se definisci l'interfaccia due volte, dattiloscritto le unisce in una.
Andrey Fedorov,

39
@jrahhali se definisci il tipo due volte, il dattiloscritto ti dà un errore
Andrey Fedorov

18
@jrahhaliinterface Point { x: number; } interface Point { y: number; }
Nahuel Greco,

20
Credo che il primo punto extends or implementsnon sia più il caso. Il tipo può essere esteso e implementato da a class. Ecco un esempio typescriptlang.org/play/…
dark_ruby

777

Aggiornamento 2019


Le risposte attuali e la documentazione ufficiale sono obsolete. E per chi non conosce TypeScript, la terminologia utilizzata non è chiara senza esempi. Di seguito è riportato un elenco di differenze aggiornate.

1. Oggetti / funzioni

Entrambi possono essere usati per descrivere la forma di un oggetto o una firma di funzione. Ma la sintassi differisce.

Interfaccia

interface Point {
  x: number;
  y: number;
}

interface SetPoint {
  (x: number, y: number): void;
}

Digitare alias

type Point = {
  x: number;
  y: number;
};

type SetPoint = (x: number, y: number) => void;

2. Altri tipi

A differenza di un'interfaccia, l'alias di tipo può essere utilizzato anche per altri tipi come primitive, sindacati e tuple.

// primitive
type Name = string;

// object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };

// union
type PartialPoint = PartialPointX | PartialPointY;

// tuple
type Data = [number, string];

3. Estendi

Entrambi possono essere estesi, ma di nuovo la sintassi differisce. Inoltre, si noti che un'interfaccia e un alias di tipo non si escludono a vicenda. Un'interfaccia può estendere un alias di tipo e viceversa.

L'interfaccia estende l'interfaccia

interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }

Alias ​​di tipo estende l'alias di tipo

type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

L'interfaccia estende l'alias di tipo

type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }

Digitare alias estende l'interfaccia

interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };

4. Strumenti

Una classe può implementare un'interfaccia o digitare un alias, entrambi nello stesso identico modo. Si noti tuttavia che una classe e un'interfaccia sono considerati progetti statici. Pertanto, non possono implementare / estendere un alias di tipo che denomina un tipo di unione.

interface Point {
  x: number;
  y: number;
}

class SomePoint implements Point {
  x = 1;
  y = 2;
}

type Point2 = {
  x: number;
  y: number;
};

class SomePoint2 implements Point2 {
  x = 1;
  y = 2;
}

type PartialPoint = { x: number; } | { y: number; };

// FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
  x = 1;
  y = 2;
}

5. Unione delle dichiarazioni

A differenza di un alias di tipo, un'interfaccia può essere definita più volte e verrà trattata come un'unica interfaccia (con i membri di tutte le dichiarazioni che vengono unite).

// These two declarations become:
// interface Point { x: number; y: number; }
interface Point { x: number; }
interface Point { y: number; }

const point: Point = { x: 1, y: 2 };

9
Se la documentazione ufficiale è obsoleta, dove possono essere confermate le informazioni fornite?
iX3,

60
Sulla base di questo post, sembra che l' unica ragione per scegliere un'interfaccia rispetto a un alias di tipo sia se si desidera utilizzare la funzione di unione delle dichiarazioni (punto 5) delle interfacce. Oltre a ciò, sono equivalenti (e direi che gli alias di tipo offrono una sintassi più concisa).
maxedison,

17
Uso sempre le interfacce per il tipo di oggetto letterale, altrimenti l'uso dei tipi ha più senso, inoltre penso che l'unione delle dichiarazioni non dovrebbe essere utilizzata in alcun modo, in realtà non mi aspetto mai che un'interfaccia venga dichiarata in un altro file del progetto con alcuni proprietà extra, il controllo del tipo è stato originariamente fatto per rendere la vita più facile non renderla più difficile con queste interfacce tipo ninja: D
Ahmed Kamal

8
Quindi, fondamentalmente, è una scelta "quasi personale" per ciò che ci fa sentire veramente a nostro agio nell'utilizzare? A parte un motivo, puoi semplicemente usare typeo interface? Sono ancora confuso su quando dovrei usare l'uno o l'altro.
Joseph Briggs,

7
Qualcuno potrebbe fornire qualche motivazione per cui vorresti unire l'interfaccia? Mi sembra potenzialmente confuso. Perché vorresti diffondere la definizione della tua interfaccia su blocchi diversi?
Vanquish46

95

A partire da TypeScript 3.2 (Nov 2018), è vero quanto segue:

inserisci qui la descrizione dell'immagine


9
Potresti fornire maggiori informazioni su come è stata generata la tabella / immagine che hai fornito? ad es. codice sorgente o collegamenti alla documentazione
iX3

23
sì, intendevo la fonte del contenuto, non la sua presentazione.
iX3,

3
Non credo che una classe possa estendere né un tipo né un'interfaccia e non riesco davvero a capire perché vorresti farlo ??
Dan King,

7
Evita di pubblicare immagini di testo, includi invece il testo effettivo direttamente nel tuo post. Le immagini di testo non sono facilmente analizzabili o ricercabili e non sono accessibili agli utenti ipovedenti.
Andrew Marshall,

2
In questa tabella mancano fonti per supportarne il contenuto e non mi baserei su di esso. Ad esempio, è possibile definire i tipi ricorsivi usando typecon alcune limitazioni (e a partire da TypeScript 3.7 anche queste limitazioni sono sparite). Le interfacce possono estendere i tipi. Le classi possono implementare tipi. Inoltre, presentare i dati come uno screenshot di una tabella li rende completamente inaccessibili alle persone con problemi di vista.
Michał Miszczyszyn,


5

Esempi con tipi:

// crea una struttura ad albero per un oggetto. Non puoi fare lo stesso con l'interfaccia a causa della mancanza di intersezione (&)

type Tree<T> = T & { parent: Tree<T> };

// digitare per limitare una variabile per assegnare solo pochi valori. Le interfacce non hanno unione (|)

type Choise = "A" | "B" | "C";

// grazie ai tipi, puoi dichiarare il tipo NonNullable grazie a un meccanismo condizionale.

type NonNullable<T> = T extends null | undefined ? never : T;

Esempi con interfaccia:

// puoi usare l'interfaccia per OOP e usare 'implements' per definire lo scheletro oggetto / classe

interface IUser {
    user: string;
    password: string;
    login: (user: string, password: string) => boolean;
}

class User implements IUser {
    user = "user1"
    password = "password1"

    login(user: string, password: string) {
        return (user == user && password == password)
    }
}

// puoi estendere le interfacce con altre interfacce

    interface IMyObject {
        label: string,
    }

    interface IMyObjectWithSize extends IMyObject{
        size?: number
    }


-2

la documentazione ha spiegato

  • Una differenza è che le interfacce creano un nuovo nome che viene utilizzato ovunque. Gli alias di tipo non creano un nuovo nome - ad esempio, i messaggi di errore non usano il nome di alias. Nelle versioni precedenti di TypeScript, gli alias di tipo non potevano essere estesi o implementati (né potevano estendere / implementare altri tipi). A partire dalla versione 2.7, gli alias di tipo possono essere estesi creando un nuovo tipo di intersezione
  • D'altra parte, se non riesci ad esprimere una forma con un'interfaccia e devi usare un tipo di unione o tupla, gli alias di tipo sono di solito la strada da percorrere.

Interfacce vs. alias di tipo

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.