Interfaces en TypeScript: de la sintaxis a interface vs type
Interfaces en TypeScript
Interface en TypeScript: sintaxis, extends, fusión y type | We.Inc
Crea una interface campo a campo, mira el type alias equivalente y aprende miembros opcionales y readonly, extends, fusión de declaraciones y cuándo encaja mejor un type alias.
Una interface da nombre a la forma de un objeto: qué propiedades tiene y de qué tipo es cada una. Marca una propiedad como opcional con ? e inmutable con readonly, parte de otra forma con extends y vuelve a abrir el mismo nombre para fusionar más miembros. Las interfaces no dejan rastro en el JavaScript compilado; solo guían al comprobador de tipos.
La sintaxis de interface de un vistazo
Quieres
Escribe
Una propiedad obligatoria
name: string;
Una propiedad opcional
nickname?: string;
Una propiedad que no se puede reasignar
readonly id: number;
Un método
greet(other: User): string;
Cualquier número de claves string
[key: string]: number;
Reutilizar otra forma
interface Admin extends User { ... }
Combinar varias formas
interface A extends B, C { ... }
Añade campos en el generador de abajo, marca opcional o readonly y copia la interface o el type alias equivalente. Las secciones de debajo cubren extends, la fusión y los pocos casos en los que elegir entre interface y type importa de verdad.
Ponle nombre a la interface y, si parte de otra, escribe ese nombre en el campo extends.
Añade una fila por propiedad, eligiendo su tipo y si es opcional o readonly.
Lee la interface y el type alias que el generador escribe a partir de las mismas filas.
Copia cualquiera de las dos versiones en tu código.
Empieza con interface para formas de objetos y recurre a type cuando necesites una unión, una tupla o un mapped type. Es la regla práctica que sugiere el propio handbook de TypeScript.
readonly solo impide reasignar esa propiedad. Los objetos anidados dentro de ella pueden cambiar, y nada se comprueba en tiempo de ejecución.
Una propiedad opcional se lee como su tipo o undefined, así que compruébala antes de usarla o dale un valor por defecto al desestructurar.
Usa nombres de interface en singular y descriptivos, como Invoice o CartItem. Un prefijo como IInvoice no aporta nada que el editor no te diga ya.
Preguntas frecuentes
¿Debo usar interface o type?
Para formas de objetos funcionan las dos y el handbook dice que es sobre todo cuestión de preferencia, y sugiere interface hasta que necesites algo que solo tiene type. Usa type para uniones, tuplas, primitivos y mapped o conditional types; usa interface cuando quieras fusión de declaraciones.
¿Qué es la fusión de declaraciones?
Declarar una interface con un nombre que ya existe le añade miembros en lugar de fallar. Las librerías se apoyan en esto para que puedas ampliar sus tipos, por ejemplo añadiendo una propiedad a Window. Un type alias con un nombre repetido es un error.
¿Qué pasa si dos interfaces fusionadas dan tipos distintos a una propiedad?
El compilador muestra un error. Con una intersección de dos tipos el conflicto no se señala en la declaración; la propiedad pasa a ser never, lo que aparece más tarde y cuesta más de rastrear.
¿Puede una interface describir una función o un array?
Sí. Una call signature como (value: string): boolean describe una función, y una index signature como [index: number]: string describe un objeto parecido a un array. Para casos simples, un type alias como type Check = (v: string) => boolean se lee con más claridad.
¿Existen las interfaces en tiempo de ejecución?
No. Se compilan a nada, así que no puedes usar instanceof con una interface ni listar sus claves. Comprueba los valores con un guard en tiempo de ejecución y anota su tipo de retorno con la interface.
extends frente a intersecciones
interface Bear extends Animal copia todos los miembros de Animal y te deja añadir más. Un type alias hace lo mismo con una intersección, type Bear = Animal & { honey: boolean }.
El handbook señala que extends puede ser más rápido para el compilador y que muestra los miembros en conflicto justo donde se declaran. Las intersecciones vienen bien para unir formas que no son tuyas.
Opcionales, readonly e index signatures
Un signo de interrogación tras el nombre hace opcional una propiedad, y su tipo de lectura incluye undefined. readonly impide asignar esa propiedad después de crearla, pero solo es una comprobación en tiempo de compilación.
Una index signature, [key: string]: number, describe diccionarios cuyas claves no puedes enumerar de antemano. Las propiedades con nombre de la misma interface deben encajar con el tipo de valor de la index signature.
Fusionar para ampliar tipos globales y de librerías
Como las interfaces se fusionan, un archivo de declaraciones puede añadir tus propios campos a formas integradas. Un caso habitual es dar a Window una propiedad que asigna un script, para que leerla pase la comprobación de tipos sin un cast.
interface frente a type alias
Qué puede hacer cada declaración
Característica
type alias
Describir la forma de un objeto
Sí
Sí
Añadir miembros redeclarando el nombre
Sí (fusión)
No, error de identificador duplicado
Partir de otra forma
Intersección con &
Unión de formas o literales
No
Sí
Dar nombre a un primitivo o una tupla
No
Sí
Mapped y conditional types
No
Sí
Patrones que escribirás a menudo
Extender una y varias interfaces
Admin recibe todos los miembros de User más los suyos; Card combina dos formas sin relación.
Fusión de declaraciones sobre Window
Colocado en un archivo .d.ts, esto hace que window.appVersion pase la comprobación de tipos en todas partes.
Index signature y call signature
Scores acepta cualquier clave string; Validator describe un valor invocable.
Generador de interfaces
Nombre de la interface
Extends (opcional)
Nombre de la propiedad {n}
Tipo de la propiedad {n}
Opcional
Readonly
Quitar la propiedad {n}
Añadir propiedad
Como interface
Como type alias
Copiar interface
Copiar type
Los nombres deben empezar por una letra, $ o _ y usar solo letras, dígitos, $ o _.