TypeScript
Tutorial TypeScript: Interfaces y su implementación
TypeScript interfaces: definición y uso. Domina la definición y uso de interfaces en TypeScript con ejemplos prácticos y detallados.
Aprende TypeScript y certifícateDefinición y sintaxis de interfaces
Después de explorar las bases de las clases en TypeScript, es momento de introducir las interfaces. Las interfaces son una herramienta poderosa que nos permite definir la forma que deben tener los objetos, actuando como contratos que garantizan que ciertas estructuras de datos cumplan con un conjunto específico de propiedades y métodos.
En esta lección, aprenderemos a definir interfaces y cómo nuestras clases pueden implementarlas para asegurar que cumplen con el contrato definido por la interfaz.
¿Qué es una interfaz?
Una interfaz en TypeScript es como un plano o un contrato. Define qué propiedades y métodos (y sus tipos) debe tener un objeto para ser considerado compatible con esa interfaz. A diferencia de las clases, las interfaces no tienen implementación (no tienen lógica dentro de los métodos, solo la firma) y no existen en el código JavaScript final después de la compilación; son una característica puramente de TypeScript para la verificación de tipos en tiempo de desarrollo.
Se declaran utilizando la palabra clave interface
.
// Definición básica de una interfaz para representar una persona
interface Person {
// Propiedades requeridas (obligatorias)
id: number;
name: string;
// Propiedad opcional (puede estar presente o no)
age?: number; // El signo ? indica que esta propiedad es opcional
// Propiedad de solo lectura (solo se puede asignar en la inicialización)
readonly passportNumber: string;
// Métodos que un objeto que cumpla esta interfaz debe tener (solo la firma)
greet(message: string): void; // Un método llamado greet que recibe un string y no devuelve nada
getDetails(): string; // Un método llamado getDetails que devuelve un string
}
- Propiedades: Defines el nombre y tipo de las propiedades. Pueden ser obligatorias (por defecto), opcionales (
?
), o de solo lectura (readonly
). La palabra clavereadonly
en una interfaz significa que un objeto que cumpla esa interfaz no debería poder modificar esa propiedad una vez que se le asigna un valor (generalmente en el momento de su creación). - Métodos: Defines solo la firma del método: su nombre, los tipos de sus parámetros y su tipo de retorno. No se incluye el cuerpo del método (la lógica).
Las interfaces son increíblemente flexibles y pueden describir la forma de casi cualquier objeto.
Implementando interfaces en clases
El propósito principal de definir interfaces es crear contratos que nuestras clases puedan prometer cumplir. Cuando una clase implementa
una interfaz, TypeScript verifica que esa clase proporcione todos los miembros requeridos (propiedades y métodos obligatorios) definidos en la interfaz, con los tipos correctos.
Para hacer que una clase implemente una interfaz, usamos la palabra clave implements
seguida del nombre de la interfaz. Una clase puede implementar una o varias interfaces (separadas por comas).
Sintaxis básica
La sintaxis para implementar una interfaz es la siguiente:
// Definimos una interfaz para un servicio de almacenamiento
interface StorageService {
// Método para guardar datos
save(key: string, value: string): void;
// Método para cargar datos
load(key: string): string | null; // Puede devolver un string o null
}
// Creamos una clase que implementa StorageService
// Esta clase DEBE tener los métodos save y load con las firmas exactas
class LocalStorageService implements StorageService {
// Las propiedades requeridas por la interfaz irían aquí si las hubiera (ej: un 'name')
// name: string = "local-storage"; // Ejemplo si la interfaz tuviera 'name: string;'
// Implementación del método save de la interfaz
save(key: string, value: string): void {
localStorage.setItem(key, value); // Lógica real del método
console.log(`Datos guardados para la clave: ${key}`);
}
// Implementación del método load de la interfaz
load(key: string): string | null {
const data = localStorage.getItem(key); // Lógica real del método
console.log(`Datos cargados para la clave: ${key}`);
return data; // Devuelve string o null, según la firma de la interfaz
}
// Podemos añadir métodos adicionales que NO estén en la interfaz
clearAll(): void {
localStorage.clear();
console.log("Limpiado todo el almacenamiento local.");
}
}
// Creamos una instancia de la clase que implementa la interfaz
const myStorage = new LocalStorageService();
myStorage.save("username", "alice"); // Usar un método implementado
const user = myStorage.load("username"); // Usar otro método implementado
if (user) {
console.log(`Usuario cargado: ${user}`);
}
myStorage.clearAll(); // Usar un método adicional de la clase
TypeScript verificará en tiempo de compilación si LocalStorageService
realmente tiene save
y load
con las firmas correctas. Si falta alguno o la firma no coincide (por ejemplo, save
devuelve number
), TypeScript mostrará un error.
Implementando Propiedades Opcionales y Readonly
Cuando una interfaz tiene propiedades opcionales (?
) o de solo lectura (readonly
), la clase que la implementa debe cumplir con esos requisitos:
- Propiedades Opcionales: La clase puede definir la propiedad opcional, pero no está obligada a hacerlo.
- Propiedades
readonly
: La clase debe definir la propiedadreadonly
y asegurarse de que solo se le asigne un valor (generalmente en el constructor).
interface Configuration {
// Propiedad obligatoria
apiUrl: string;
// Propiedad opcional
timeout?: number;
// Propiedad de solo lectura
readonly version: string;
}
class ApiService implements Configuration {
apiUrl: string; // Implementa propiedad obligatoria
timeout?: number; // Implementa propiedad opcional (podríamos omitirla)
readonly version: string; // Implementa propiedad readonly
constructor(url: string, apiVersion: string, requestTimeout?: number) {
this.apiUrl = url;
this.version = apiVersion; // Asignamos el valor a la propiedad readonly aquí
this.timeout = requestTimeout; // Asignamos valor a la opcional si existe
}
// Método para ilustrar uso (no requerido por la interfaz)
fetchData(): void {
console.log(`Workspaceing from ${this.apiUrl} (v${this.version}) with timeout ${this.timeout || 'default'}`);
// No podríamos hacer: this.version = "new-version"; // Error porque version es readonly
}
}
const service = new ApiService("https://api.example.com", "1.0", 5000);
service.fetchData();
const simpleService = new ApiService("https://api.another.com", "2.0"); // Omitimos el timeout opcional
simpleService.fetchData();
Implementando múltiples interfaces
Una clase puede implementar múltiples interfaces simultáneamente, lo que permite componer comportamientos de diferentes contratos:
// Interfaz para algo que se puede guardar
interface Saveable {
save(): boolean; // Devuelve true si se guardó correctamente
}
// Interfaz para algo que se puede cargar
interface Loadable {
load(id: string): boolean; // Carga por ID, devuelve true si se encontró
}
// Nuestra clase que implementa ambas interfaces
class UserProfileManager implements Saveable, Loadable {
userId: string | null = null;
userData: any = null; // Usamos 'any' temporalmente, idealmente sería un tipo más específico
constructor(initialUserId?: string) {
if (initialUserId) {
this.load(initialUserId); // Intentar cargar al iniciar
}
}
// Implementación del método save de Saveable
save(): boolean {
if (this.userId && this.userData) {
console.log(`Guardando datos para usuario ${this.userId}...`);
// Aquí iría la lógica real para guardar (ej: a un archivo, API)
return true; // Simulación de guardado exitoso
}
console.log("No hay datos o ID de usuario para guardar.");
return false;
}
// Implementación del método load de Loadable
load(id: string): boolean {
console.log(`Cargando datos para usuario ${id}...`);
// Aquí iría la lógica real para cargar (ej: desde un archivo, API)
// Simulación: encontrar datos si el ID es "user123"
if (id === "user123") {
this.userId = id;
this.userData = { name: "Charlie", age: 40 }; // Datos cargados
console.log("Usuario cargado exitosamente.");
return true; // Simulación de carga exitosa
}
console.log("Usuario no encontrado.");
this.userId = null;
this.userData = null;
return false; // Simulación de carga fallida
}
}
// Creamos una instancia del Manager
const manager = new UserProfileManager();
manager.load("user123"); // Llama al método load
manager.save(); // Llama al método save
manager.load("user456"); // Llama al método load (fallará)
manager.save(); // Llama al método save (fallará)
Implementación con propiedades privadas
Las interfaces solo definen la estructura pública de una clase. Podemos implementar una interfaz y añadir propiedades o métodos privados adicionales:
interface ICounter {
count: number;
increment(): void;
decrement(): void;
reset(): void;
}
class Counter implements ICounter {
count: number;
private initialValue: number;
constructor(initialValue: number = 0) {
this.count = initialValue;
this.initialValue = initialValue;
}
increment(): void {
this.count++;
}
decrement(): void {
this.count--;
}
reset(): void {
this.count = this.initialValue;
}
// Método privado adicional que no está en la interfaz
private logCount(): void {
console.log(`Current count: ${this.count}`);
}
}
Implementación con accesores
Podemos implementar propiedades de interfaz utilizando getters y setters en la clase:
interface IPerson {
firstName: string;
lastName: string;
fullName: string;
}
class Person implements IPerson {
private _firstName: string;
private _lastName: string;
constructor(firstName: string, lastName: string) {
this._firstName = firstName;
this._lastName = lastName;
}
get firstName(): string {
return this._firstName;
}
set firstName(value: string) {
this._firstName = value;
}
get lastName(): string {
return this._lastName;
}
set lastName(value: string) {
this._lastName = value;
}
get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
}
const person = new Person("John", "Doe");
console.log(person.fullName); // Output: John Doe
person.firstName = "Jane";
console.log(person.fullName); // Output: Jane Doe
Caso práctico: implementación de interfaces para componentes
Las interfaces son especialmente útiles cuando desarrollamos componentes reutilizables:
interface IComponent {
render(): string;
update(props: any): void;
}
class Button implements IComponent {
private label: string;
private onClick: () => void;
constructor(label: string, onClick: () => void) {
this.label = label;
this.onClick = onClick;
}
render(): string {
return `<button class="btn" onclick="handleClick()">${this.label}</button>`;
}
update(props: { label?: string; onClick?: () => void }): void {
if (props.label) {
this.label = props.label;
}
if (props.onClick) {
this.onClick = props.onClick;
}
}
// Método específico de Button que no está en la interfaz
handleClick(): void {
this.onClick();
}
}
class Image implements IComponent {
private src: string;
private alt: string;
constructor(src: string, alt: string) {
this.src = src;
this.alt = alt;
}
render(): string {
return `<img src="${this.src}" alt="${this.alt}" />`;
}
update(props: { src?: string; alt?: string }): void {
if (props.src) {
this.src = props.src;
}
if (props.alt) {
this.alt = props.alt;
}
}
}
La implementación de interfaces en clases es una práctica fundamental en TypeScript que promueve el diseño orientado a contratos y facilita la creación de código más modular, mantenible y fácil de probar.
Extensión de interfaces
Las interfaces en TypeScript no solo pueden ser implementadas por clases, sino que también pueden extenderse entre sí para crear estructuras más complejas y reutilizables. La extensión de interfaces nos permite construir interfaces más específicas a partir de otras más generales, siguiendo el principio de composición que es fundamental en el diseño de software.
Sintaxis básica de extensión
Para extender una interfaz, utilizamos la palabra clave extends
:
interface Animal {
name: string;
age: number;
}
interface Pet extends Animal {
owner: string;
vaccinated: boolean;
}
En este ejemplo, la interfaz Pet
hereda todas las propiedades de Animal
(name
y age
) y añade sus propias propiedades (owner
y vaccinated
). Cualquier objeto que implemente Pet
deberá proporcionar valores para las cuatro propiedades.
const myDog: Pet = {
name: "Rex",
age: 3,
owner: "Alice",
vaccinated: true
};
Extendiendo múltiples interfaces
Una interfaz puede extender de múltiples interfaces a la vez, combinando todos sus miembros.
// Interfaz para identificar algo
interface Identifiable {
id: string;
}
// Interfaz para algo que tiene una fecha de creación
interface Timestamped {
createdAt: Date;
}
// Interfaz para un Usuario (hereda de Identifiable y Timestamped)
// Un User DEBE tener id (de Identifiable) y createdAt (de Timestamped)
interface UserProfileInterface extends Identifiable, Timestamped {
name: string; // Además, un UserProfile tiene un nombre
}
// Una clase que implemente UserProfileInterface debe tener id, createdAt y name
class BasicUser implements UserProfileInterface {
id: string; // De Identifiable
createdAt: Date; // De Timestamped
name: string; // De UserProfileInterface
constructor(id: string, name: string) {
this.id = id;
this.name = name;
this.createdAt = new Date(); // Inicializamos el miembro heredado
}
}
const basicUser = new BasicUser("user-007", "James Bond");
console.log(`${basicUser.name} (ID: ${basicUser.id}) created at ${basicUser.createdAt.toDateString()}`);
Esta técnica es especialmente útil para crear interfaces modulares que pueden combinarse según las necesidades específicas de cada caso.
Redefinición de propiedades
Al extender interfaces, podemos redefinir propiedades para hacerlas más específicas, siempre que el nuevo tipo sea compatible con el original:
interface Shape {
color: string;
area(): number;
}
interface Circle extends Shape {
radius: number;
// Redefinimos el método area con una firma más específica
area(): number;
}
class CircleImpl implements Circle {
color: string;
radius: number;
constructor(color: string, radius: number) {
this.color = color;
this.radius = radius;
}
area(): number {
return Math.PI * this.radius * this.radius;
}
}
Extensión y sobrescritura de propiedades opcionales
Podemos convertir propiedades opcionales en obligatorias al extender interfaces:
interface Config {
endpoint: string;
timeout?: number;
retries?: number;
}
interface StrictConfig extends Config {
// Convertimos propiedades opcionales en obligatorias
timeout: number;
retries: number;
// Añadimos nuevas propiedades
logLevel: 'debug' | 'info' | 'warn' | 'error';
}
const devConfig: Config = {
endpoint: "https://api.dev.example.com"
// timeout y retries son opcionales
};
const prodConfig: StrictConfig = {
endpoint: "https://api.example.com",
timeout: 5000, // Ahora es obligatorio
retries: 3, // Ahora es obligatorio
logLevel: "error"
};
Interfaces anidadas y extensión
Las interfaces pueden contener definiciones de otras interfaces, y estas también pueden extenderse:
interface Address {
street: string;
city: string;
zipCode: string;
country: string;
}
interface Person {
name: string;
address: Address;
}
interface Employee extends Person {
employeeId: string;
department: string;
// Podemos extender la definición anidada
address: Address & {
officeNumber?: string;
};
}
const employee: Employee = {
name: "John Smith",
employeeId: "E12345",
department: "Engineering",
address: {
street: "123 Main St",
city: "San Francisco",
zipCode: "94105",
country: "USA",
officeNumber: "4B"
}
};
Interfaces vs. tipos: cuándo usar cada uno
Ya conoces los alias de tipo (type
) para dar nombres a tipos, y ahora las interfaces (interface
) para definir la forma de los objetos y clases. A menudo, pueden parecer muy similares, especialmente para definir la estructura de un objeto:
Sintaxis básica
La sintaxis para definir ambos constructos es ligeramente diferente:
// Usando Type Alias para la forma de un punto
type PointType = {
x: number;
y: number;
};
// Usando Interface para la forma de un punto
interface PointInterface {
x: number;
y: number;
}
// Ambos funcionan para tipar variables y objetos literales
const point1: PointType = { x: 10, y: 20 };
const point2: PointInterface = { x: 30, y: 40 };
// Y son estructuralmente compatibles (puedes asignar uno al otro si tienen la misma forma)
const point3: PointType = point2; // OK
const point4: PointInterface = point1; // OK
Sin embargo, hay diferencias clave en lo que pueden describir y cómo se comportan en cuanto a extensibilidad y uso con clases:
- Lo que pueden describir:
interface
: Principalmente describe la forma de objetos. Puede tener propiedades y firmas de métodos.type
: Puede dar nombre a cualquier tipo, incluyendo primitivos (type UserId = string;
), uniones (type Status = "active" | "inactive";
), tuplas (type Coordinates = [number, number];
), firmas de funciones (type Comparator = (a, b) => number;
), y la forma de objetos.
- Extensibilidad y Clases:
interface
: Puede ser extendida por otras interfaces (interface Pet extends Animal {}
) y implementada por clases (class Dog implements Pet {}
). Están diseñadas para la herencia y la implementación de contratos en OOP.type
: Puede dar nombre a la forma de un objeto, pero no puede ser implementado directamente por una clase usandoimplements
en el mismo sentido. No tienen el mecanismoextends
nativo para crear herencia de formas de objeto (aunque puedes combinar tipos usando intersecciones&
, que es un concepto diferente).
Guía práctica: ¿Cuándo usar cada uno?
Basándonos en las diferencias anteriores, aquí hay una guía práctica para decidir cuándo usar interfaces y cuándo usar tipos:
Usa interfaces cuando:
- Defines clases que implementarán la estructura:
interface Repository<T> {
findAll(): Promise<T[]>;
findById(id: string): Promise<T | null>;
save(item: T): Promise<T>;
}
class UserRepository implements Repository<User> {
// Implementación...
}
- Creas bibliotecas o APIs públicas que otros desarrolladores pueden necesitar extender:
// En tu biblioteca
interface Theme {
primaryColor: string;
secondaryColor: string;
}
// Los consumidores pueden extender
interface CustomTheme extends Theme {
tertiaryColor: string;
fontFamily: string;
}
- Necesitas fusionar declaraciones del mismo nombre:
// Definición base
interface Config {
apiUrl: string;
}
// En otro archivo o módulo
interface Config {
timeout: number;
}
// Uso combinado
const config: Config = {
apiUrl: "https://api.example.com",
timeout: 3000
};
Usa tipos cuando:
- Necesitas uniones o intersecciones:
type Result<T> = SuccessResult<T> | ErrorResult;
type UserWithRoles = User & {
roles: string[];
permissions: string[];
};
- Trabajas con tuplas o arrays específicos:
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type Point2D = [number, number];
type RGB = [number, number, number];
type RGBA = [...RGB, number];
- Necesitas tipos utilitarios o transformaciones:
type Nullable<T> = T | null;
type KeysOf<T> = keyof T;
type UserKeys = KeysOf<User>; // "id" | "name" | "email"
- Defines alias para tipos primitivos o funciones:
type UserId = string;
type ValidationFunction<T> = (value: T) => boolean;
type EventHandler = (event: Event) => void;
Ejemplo práctico: Modelado de una aplicación
Veamos un ejemplo práctico que muestra cómo combinar interfaces y tipos de manera efectiva:
// Tipos para valores primitivos y uniones
type UserId = string;
type UserRole = "admin" | "editor" | "viewer";
type ValidationResult = "valid" | "invalid" | "pending";
// Interfaces para estructuras de objetos
interface UserBase {
id: UserId;
name: string;
email: string;
}
interface AdminUser extends UserBase {
role: "admin";
permissions: string[];
}
interface RegularUser extends UserBase {
role: "editor" | "viewer";
department: string;
}
// Tipo para unión de diferentes usuarios
type User = AdminUser | RegularUser;
// Interfaz para servicios (será implementada)
interface UserService {
getUser(id: UserId): Promise<User | null>;
validateUser(user: User): ValidationResult;
updateUser(user: User): Promise<User>;
}
// Implementación concreta
class ApiUserService implements UserService {
async getUser(id: UserId): Promise<User | null> {
// Implementación...
return null;
}
validateUser(user: User): ValidationResult {
// Validación basada en el tipo de usuario
if (user.role === "admin") {
// Acceso a propiedades específicas de AdminUser
return user.permissions.length > 0 ? "valid" : "invalid";
} else {
// Acceso a propiedades específicas de RegularUser
return user.department ? "valid" : "invalid";
}
}
async updateUser(user: User): Promise<User> {
// Implementación...
return user;
}
}
Consideraciones de compatibilidad
Es importante destacar que interfaces y tipos son estructuralmente compatibles entre sí si sus estructuras coinciden:
interface IPoint {
x: number;
y: number;
}
type TPoint = {
x: number;
y: number;
};
// Esto es válido - son estructuralmente equivalentes
const p1: IPoint = { x: 10, y: 20 };
const p2: TPoint = p1;
Recomendación general
Una regla práctica que muchos equipos de desarrollo siguen es:
- Usa
interface
principalmente cuando estés definiendo la forma de un objeto o el contrato que una clase va a cumplir. Son ideales para la programación orientada a objetos y la definición de estructuras que se implementarán. - Usa
type
cuando necesites dar nombre a cualquier otro tipo (primitivos, uniones simples, tuplas, firmas de funciones) o cuando quieras definir la forma de un objeto de manera más flexible (aunque para formas de objeto simples, la elección entreinterface
ytype
es a menudo una cuestión de preferencia o convención del equipo).
Ambas herramientas son esenciales en TypeScript y las verás combinadas a menudo en proyectos reales. La clave es entender sus propósitos principales y sus diferencias para usarlas de forma efectiva.
Otros ejercicios de programación de TypeScript
Evalúa tus conocimientos de esta lección Interfaces y su implementación con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Funciones
Reto composición de funciones
Reto tipos especiales
Reto tipos genéricos
Módulos
Polimorfismo
Funciones TypeScript
Interfaces
Funciones puras
Reto namespaces
Funciones flecha
Polimorfismo
Operadores
Conversor de unidades
Funciones flecha
Control de flujo
Herencia
Clases
Proyecto validación de tipado
Clases y objetos
Encapsulación
Herencia
Proyecto sistema de votación
Reto genéricos con clases
Inmutabilidad
Interfaces
Funciones de alto orden
Reto map y filter
Control de flujo
Interfaces
Reto funciones orden superior
Herencia y clases abstractas
Reto tipos mapped
Herencia de clases
Reto funciones puras
Variables y constantes
Introducción a TypeScript
Reto testing unitario
Funciones de primera clase
Clases
OOP y CRUD en TypeScript
Interfaces y su implementación
Tipos genéricos
Namespaces
Operadores y expresiones
Proyecto generador de contraseñas
Reto unión e intersección
Encapsulación
Tipos de unión e intersección
Tipos de unión e intersección
Reto hola mundo en TS
Variables y constantes
Funciones puras
Control de flujo
Introducción a TypeScript
Resolución de módulos
Control de flujo
Reto tipos de utilidad
Reto tipos literales y condicionales
Reto exportar e importar
Propiedades y métodos
Tipos de utilidad
Clases y objetos
Tipos de datos, variables y constantes
Proyecto Minigestor de tareas
Operadores
Funciones flecha y contexto
Proyecto Inventario de productos
Funciones
Reto type aliases
Funciones de alto orden
Funciones y parámetros tipados
Tipos literales
Reto enums
Tipos de utilidad
Modificadores de acceso y encapsulación
Polimorfismo
Tipos genéricos
Reto módulos
Tipos literales
Inmutabilidad
Proyecto Generator de datos
Variables y constantes
Funciones de primera clase
Todas las lecciones de TypeScript
Accede a todas las lecciones de TypeScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Typescript
Introducción Y Entorno
Instalación Y Configuración De Typescript
Introducción Y Entorno
Tipos De Datos, Variables Y Constantes
Sintaxis
Operadores Y Expresiones
Sintaxis
Control De Flujo
Sintaxis
Funciones Y Parámetros Tipados
Sintaxis
Funciones Flecha Y Contexto
Sintaxis
Enums
Sintaxis
Type Aliases Y Aserciones De Tipo
Sintaxis
Clases Y Objetos
Programación Orientada A Objetos
Interfaces Y Su Implementación
Programación Orientada A Objetos
Modificadores De Acceso Y Encapsulación
Programación Orientada A Objetos
Herencia Y Clases Abstractas
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Decoradores Básicos
Programación Orientada A Objetos
Propiedades Y Métodos
Programación Orientada A Objetos
Inmutabilidad
Programación Funcional
Funciones Puras Y Efectos Secundarios
Programación Funcional
Funciones De Primera Clase
Programación Funcional
Funciones De Alto Orden
Programación Funcional
Conceptos Básicos E Inmutabilidad
Programación Funcional
Funciones De Primera Clase Y Orden Superior
Programación Funcional
Composición De Funciones
Programación Funcional
Métodos Funcionales De Arrays (Map, Filter, Reduce)
Programación Funcional
Tipos Literales Y Tipos Condicionales
Tipos Intermedios Y Avanzados
Tipos Genéricos Básicos
Tipos Intermedios Y Avanzados
Tipos De Unión E Intersección
Tipos Intermedios Y Avanzados
Tipos De Utilidad (Partial, Required, Pick, Etc)
Tipos Intermedios Y Avanzados
Unknown, Never Y Tipos Especiales
Tipos Intermedios Y Avanzados
Tipos Mapped
Tipos Intermedios Y Avanzados
Genéricos Con Clases E Interfaces
Tipos Intermedios Y Avanzados
Módulos
Namespaces Y Módulos
Namespaces
Namespaces Y Módulos
Resolución De Módulos
Namespaces Y Módulos
Exportación E Importación De Módulos
Namespaces Y Módulos
Introducción A Módulos
Namespaces Y Módulos
Testing Unitario En Typescript
Testing
En esta lección
Objetivos de aprendizaje de esta lección
- Definir contratos de objeto con
interface
. - Implementar interfaces en clases con
implements
. - Implementar múltiples interfaces en una clase.
- Extender interfaces para reutilizar contratos.
- Comprender la diferencia básica entre
interface
ytype
.