Tipos de utilidad de TypeScript

Los tipos de utilidad (Utility Types) son una serie de tipos avanzados integrados en TypeScript.

Ayudan a los desarrolladores a crear y transformar tipos rápidamente, mejorando la reutilización del código y la seguridad de tipos.

Los tipos de utilidad son esencialmente tipos genéricos, implementados mediante tipos mapeados y tipos condicionales.


Contexto Título Tipos de utilidad de TypeScript Tipos primitivos Tipos primitivos interface User { id: number; name: string; email: string; } Flecha Tipos de utilidad Tipos de utilidad Partial<T> - Todos opcionales Required<T> - Todos requeridos Readonly<T> - Todos de solo lectura Pick<T,K> - Seleccionar propiedades Omit<T,K> - Excluir propiedades Flecha Resultado Tipo de resultado type Result = { id?: number; name?: string; email?: string; } Parte inferior Tipos de utilidad comunes Primera fila Partial<T> Todas las propiedades opcionales { a?: T } Required<T> Todas las propiedades requeridas { -? } Readonly<T> Todas las propiedades de solo lectura { readonly } Pick<T,K> Seleccionar propiedades específicas { pick } Segunda fila (énfasis de corrección) Record<K,T> Construir tipos de objeto Omit<T,K> Excluir propiedades específicas Definición de flecha

¿Por qué necesitamos tipos de utilidad?

En el desarrollo real de TypeScript, a menudo necesitamos crear nuevos tipos basados en tipos existentes.

Crear estos tipos manualmente no solo es tedioso, sino que también es propenso a errores.

Los tipos de utilidad ofrecen una forma declarativa de transformar y crear tipos, lo que mejora en gran medida la eficiencia del desarrollo.

Explicación del concepto:Los tipos de utilidad son una serie de tipos genéricos predefinidos en TypeScript. Utilizan tipos mapeados y tipos condicionales para lograr la transformación y generación de tipos.


Partial<T> - Propiedades opcionales

Partial establece todas las propiedades del tipo T como opcionales.

Esto es muy útil al crear objetos de actualización parcial o al manejar datos de formularios.

Ejemplo

// Definir la interfaz de usuario, contiene propiedades requeridas
interface User {
    // ID de usuario
    id: number;
    // Nombre de usuario
    name: string;
    // Correo electrónico del usuario
    email: string;
}

// Partial: convierte todas las propiedades en opcionales
// En el tipo transformado, todas las propiedades son opcionales
type PartialUser = Partial<User>;

// Usar el tipo PartialUser
// Se pueden proporcionar solo algunas propiedades, no es necesario proporcionarlas todas
var user: PartialUser = { name: "Alice" };

console.log("Usuario parcial: " + JSON.stringify(user));

Resultado de la ejecución:

部分用户: {"name":"Alice"}

Escenarios de aplicación:Partial se usa comúnmente para actualizar datos de objetos. Por ejemplo: al actualizar solo una parte de la información del usuario, no es necesario pasar el objeto de usuario completo.


Required<T> - Propiedades requeridas

Required es lo opuesto a Partial, establece todas las propiedades opcionales como requeridas.

Se usa cuando se necesita asegurar que el objeto contenga todas las propiedades.

Ejemplo

// Definir la interfaz de configuración, las propiedades son opcionales
interface Config {
    // Dirección del servidor
    host?: string;
    // Número de puerto
    port?: number;
}

// Required: convierte todas las propiedades opcionales en requeridas
// En el tipo transformado, todas las propiedades son requeridas
type RequiredConfig = Required<Config>;

// Usar el tipo RequiredConfig
// Se deben proporcionar todas las propiedades
var config: RequiredConfig = { host: "localhost", port: 8080 };

console.log("Configuración: " + JSON.stringify(config));

Resultado de la ejecución:

配置: {"host":"localhost","port":8080}

Explicación:Required no solo elimina las propiedades opcionales (?), sino que también elimina el modificador readonly.


Readonly<T> - Propiedades de solo lectura

Readonly establece todas las propiedades como de solo lectura.

Es muy útil para objetos que no se pueden modificar después de su creación.

Ejemplo

// Definir la interfaz de usuario
interface User {
    // Nombre de usuario
    name: string;
    // Edad del usuario
    age: number;
}

// Readonly: convierte todas las propiedades en solo lectura
// En el tipo transformado, ninguna propiedad puede modificarse
type ReadonlyUser = Readonly<User>;

// Crear un objeto de usuario de solo lectura
var user: ReadonlyUser = { name: "Alice", age: 25 };

// Intentar modificar una propiedad de solo lectura provocará un error
// user.name = "Bob"; // Error: las propiedades de solo lectura no se pueden modificar

console.log("Usuario de solo lectura: " + JSON.stringify(user));

Escenarios de aplicación:Readonly se usa comúnmente para definir objetos de configuración, mapeos de valores de enumeración y otros datos que no se desea modificar.


Pick<T, K> - Seleccionar propiedades

Pick selecciona las propiedades especificadas K del tipo T para formar un nuevo tipo.

Se usa cuando solo necesitas algunas propiedades de un tipo.

Ejemplo

// Definir la interfaz de usuario completa
interface User {
    // ID de usuario
    id: number;
    // Nombre de usuario
    name: string;
    // Correo electrónico del usuario
    email: string;
    // Contraseña del usuario
    password: string;
}

// Pick: selecciona las propiedades especificadas para formar un nuevo tipo
// Seleccionar las propiedades id y name de User
type UserBasicInfo = Pick<User, "id" | "name">;

// Usar el tipo seleccionado
var user: UserBasicInfo = { id: 1, name: "Alice" };

console.log("Información básica del usuario: " + JSON.stringify(user));

Resultado de la ejecución:

用户基本信息: {"id":1,"name":"Alice"}

Comparación:Pick y Partial se pueden combinar para crear tipos que solo contienen algunas propiedades opcionales.


Omit<T, K> - Excluir propiedades

Omit excluye las propiedades especificadas K del tipo T y devuelve un nuevo tipo formado por las propiedades restantes.

Es lo opuesto a Pick, se usa para eliminar propiedades innecesarias.

Ejemplo

// Definir la interfaz de usuario completa
interface User {
    // ID de usuario
    id: number;
    // Nombre de usuario
    name: string;
    // Correo electrónico del usuario
    email: string;
    // Contraseña del usuario
    password: string;
}

// Omit: excluye las propiedades especificadas
// Excluir la propiedad password de User
type UserWithoutPassword = Omit<User, "password">;

// Usar el tipo resultante de la exclusión
var user: UserWithoutPassword = { id: 1, name: "Alice", email: "[email protected]" };

console.log("Usuario sin contraseña: " + JSON.stringify(user));

Resultado de la ejecución:

无密码用户: {"id":1,"name":"Alice","email":"[email protected]"}

Consejo:Omit es la operación inversa de Pick. Usa Omit cuando necesites excluir pocas propiedades y usa Pick cuando necesites seleccionar pocas propiedades.


Record<K, T> - Construir tipos de objeto

Record construye un tipo de objeto, donde el tipo de las claves es K y el tipo de los valores es T.

Se usa comúnmente para crear mapeos de pares clave-valor, tipos de diccionario, etc.

Ejemplo

// Definir el tipo de rol
type Role = "admin" | "user" | "guest";

// Record: construye un tipo de objeto
// La clave es de tipo Role, el valor es de tipo matriz de cadenas
type RolePermissions = Record<Role, string[]>;

// Usar Record para crear un mapeo de permisos
var permissions: RolePermissions = {
    // El administrador tiene todos los permisos
    admin: ["read", "write", "delete"],
    // El usuario normal tiene permisos de lectura y escritura
    user: ["read", "write"],
    // El visitante solo tiene permiso de lectura
    guest: ["read"]
};

console.log("Permisos del administrador: " + permissions.admin);
console.log("Permisos del visitante: " + permissions.guest);

Resultado de la ejecución:

管理员权限: read,write,delete
访客权限: read

Escenarios de aplicación:Record se usa comúnmente en escenarios como mapeos de configuración, mapeos de estado, mapeos de permisos, donde se necesita buscar valores rápidamente según la clave.


Exclude<T, U> - Excluir tipos

Exclude excluye del tipo T los tipos que se pueden asignar al tipo U.

Se utiliza principalmente para tipos de unión, para excluir miembros de tipo específicos.

Ejemplo

// Definir tipo de unión, incluye a, b, c, d
type T = "a" | "b" | "c" | "d";

// Exclude: excluir tipos específicos de T
// Excluir "a", "b", "c", solo conservar "d"
type NonABC = Exclude<T, "a" | "b" | "c">;

// Usando el tipo excluido, solo se puede asignar "d"
var value: NonABC = "d";

console.log("Valor: " + value);

Resultado:

值: d

Explicación:El principio de Exclude es: si un tipo en T se puede asignar a U, se elimina de T.


Extract<T, U> - Extraer tipos

Extract es lo opuesto a Exclude, extrae del tipo T los tipos que se pueden asignar al tipo U.

Se utiliza para filtrar miembros específicos en tipos de unión.

Ejemplo

// Definir tipo de unión mixto, incluye strings y números
type T = "a" | "b" | "c" | 1 | 2 | 3;

// Extract: extraer tipos específicos de T
// Extraer todos los tipos string: "a", "b", "c"
type Letters = Extract<T, string>;

// Usar el tipo extraído
var letter: Letters = "a";

console.log("Letras: " + letter);

Resultado:

字母: a

Comparación:Extract y Exclude son complementarios. Extract(T, U) es equivalente a Exclude(T, Exclude&lt;T, U&gt;).


NonNullable<T> - Excluir valores nulos

NonNullable excluye null y undefined del tipo T.

Se usa cuando se necesita asegurar que el tipo no contenga valores nulos.

Ejemplo

// Definir tipo mixto, incluye string, null, undefined, number
type T = string | null | undefined | number;

// NonNullable: excluir null y undefined
// Después de la conversión, solo se conservan string y number
type NotNull = NonNullable<T>;

// Usar el tipo no nulo
var value: NotNull = "hello";
value = 42;

// Intentar asignar null causará un error
// value = null; // Error: no se puede asignar null

console.log("Valor: " + value);

Explicación:NonNullable&lt;T&gt; es equivalente a Exclude&lt;T, null | undefined&gt;.


ReturnType<T> - Obtener el tipo de retorno

ReturnType obtiene el tipo de retorno del tipo de función T.

Se usa frecuentemente para extraer el tipo de retorno de funciones existentes.

Ejemplo

// Definir función para obtener el usuario
function getUser() {
    return { name: "Alice", age: 25 };
}

// Definir función para obtener la configuración
function getConfig() {
    return { host: "localhost", port: 8080 };
}

// ReturnType: obtener el tipo de retorno de la función
// Extraer el tipo de retorno de la función getUser
type UserType = ReturnType<typeof getUser>;
// Extraer el tipo de retorno de la función getConfig
type ConfigType = ReturnType<typeof getConfig>;

// Usar el tipo de retorno extraído para crear un objeto
var user: UserType = { name: "Bob", age: 30 };
var config: ConfigType = { host: "example.com", port: 3000 };

console.log("Usuario: " + JSON.stringify(user));
console.log("Configuración: " + JSON.stringify(config));

Resultado:

Usuario: {"name":"Bob","age":30}
配置: {"host":"example.com","port":3000}

Consejo:T en ReturnType&lt;T&gt; debe ser un tipo de función. Puedes usar typeof para obtener el tipo de la función.


Notas

  • Los tipos utilitarios son todos genéricos:Se deben pasar parámetros de tipo concretos al usarlos
  • Solo lectura y opcional:Los tipos utilitarios se pueden combinar, como Partial&lt;Readonly&lt;T&gt;&gt;
  • Tipos integrados:Estos tipos utilitarios están integrados en TypeScript, no requieren instalación
  • Tipos utilitarios personalizados:Se pueden crear tipos utilitarios personalizados basados en tipos mapeados y tipos condicionales

Avanzado:Si los tipos utilitarios integrados no satisfacen las necesidades, se puede consultar el código fuente de TypeScript para implementar tus propios tipos utilitarios personalizados.


Resumen

Los tipos utilitarios de TypeScript son una parte importante del sistema de tipos.

  • Partial<T>:Hacer que todas las propiedades sean opcionales
  • Required<T>:Hacer que todas las propiedades sean obligatorias
  • Readonly<T>:Hacer que todas las propiedades sean de solo lectura
  • Pick<T,K>:Seleccionar propiedades específicas
  • Omit<T,K>:Excluir propiedades específicas
  • Record<K,T>:Construir tipo de objeto
  • Exclude/Extract:Filtrado de tipos
  • NonNullable:Excluir null y undefined
  • ReturnType:Obtener el tipo de retorno de una función

Mejores prácticas:El buen uso de los tipos utilitarios puede hacer que el código sea más seguro en cuanto a tipos, reducir definiciones de tipos duplicadas y mejorar el mantenimiento del código.


Otras extensiones