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.
¿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
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
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
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
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
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
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
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
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<T, U>).
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
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<T> es equivalente a Exclude<T, null | undefined>.
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
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<T> 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<Readonly<T>>
- 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