Índice de contenidos
- Introducción
- Partial
- Pick
- Omit
- Record
- Exclude
- Extract
- Required
- Readonly
- NonNullable
- ReturnType
- Awaited
- Conclusión
Introducción
Como vimos en mi último articulo en el que hablaba sobre genéricos en Typescript, TypeScript no se limita al tipado estático simple, si no que nos proporciona una gran cantidad de herramientas que nos agilizan el desarrollo y hacen este más legible y simple.
En este artículo te voy a enseñar algunas de sus utilidades que te van a ayudar a mejorar tus desarrollos. Vamos a ello:
Partial
Partial
nos permite tipar haciendo opcionales todas las propiedades del genérico que recibe como tipo. Podríamos decir que transforma un tipado estricto donde tienes que implementar todas las propiedades en un tipado menos agresivo donde te permite ‘elegir’ las propiedades que necesites.
interface TShirt {
size: string,
color: string,
frontText: string,
backText: string
}
const customTShirt: Partial<TShirt> = {
size: 'Small',
color: 'blue'
frontText: 'Change de future'
}
const otherCustomTShirt: Partial<TShirt> = {
size: 'Large',
color: 'green'
backText: 'Change de future'
}
Pick
Pick
nos permite tipar seleccionando las propiedades que queramos del genérico que le proporcionamos. Es decir, es como una versión simplificada.
type BasicTShirt = Pick<TShirt, 'size' | 'color'>
const basicTShirt: BasicTShirt = {
size: 'Large',
color: 'white'
}
Omit
Omit
nos permite tipar omitiendo las propiedades que le indiquemos del genérico que le proporcionamos. Digamos que funciona igual que Pick
pero esta vez las propiedades que le indicamos son las que no queremos que se incluyan en el nuevo tipo.
type TShitContent = Omit<TShirt, 'size' | 'color'>
const basicTShirt: BasicTShirt = {
frontText: 'Change de future',
backText: 'Change de future'
}
Record
Record
nos permite tipar especificando el tipo de claves y el tipo de valor. Este caso se entiende mejor viendo un ejemplo.
interface TShirtModel {
color: string,
frontText: string,
backText: string
}
type Seasons = "summer" | "winter" | "spring" | "autumn"
const collections: Record<Seasons, TShirtModel> = {
summer: { color: 'orange' , frontText: 'Summer', backText: 'Summer days'},
winter: { color: 'blue' , frontText: 'Winter', backText: 'Winter days'},
spring: { color: 'green' , frontText: 'Spring', backText: 'Spring days'},
autumn: { color: 'brown' , frontText: 'Autumn', backText: 'Autumn days'},
}
Exclude
Exclude
nos permite tipar excluyendo el tipo que le pasamos como segundo argumento al genérico que recibe como primer argumento.
interface TShirt {
size: string,
color: string,
frontText: string,
backText: string
}
interface DeliveryPoint {
address: string,
city: string,
postalCode: string
}
interface PaymentMethod {
type: string,
provider: string
}
type FullOrderInformation = TShirt & DeliveryPoint & PaymentMethod
const fullInfo: FullOrderInformation = {
size: 'Medium',
color: 'Black',
frontText: 'Hello',
backText: 'Bye',
address: 'some direction',
city: 'Madrid',
postalCode: '32556',
type: 'Credit Card',
provider: 'Visa'
}
type DistrubutorInformation = Exclude<FullOrderInformation, PaymentMethod>
const distributorInfo: DistributorInformation = {
size: 'Medium',
color: 'Black',
frontText: 'Hello',
backText: 'Bye',
address: 'some direction',
city: 'Madrid',
postalCode: '32556'
}
Extract
Extract
nos permite tipar manteniendo las propiedades que se pueden asignar al tipo extraído.
Podríamos decir que extract busca las propiedades comunes entre los tipos proporcionados.
type TShirtMaterials = 'Cotton' | 'Polyester' | 'Linen'
type PantMaterials = 'Cotton' | 'Polyester' | 'Nylon'
type CommonMaterials = Extract<TShirtMaterials, PantMaterials>
const commonMaterials: CommonMaterials = 'Cotton' | 'Polyester'
Required
Required
establece todas las propiedades del tipo como requeridas.
interface TShirt {
size: string,
color: string,
frontText?: string,
backText?: string
}
type FrontAndBackTextTShirt = Required<TShirt>
const basicTShirt: TShirt = {
size: 'Large'
color: 'yellow'
}
const otherTShirt: FrontAndBackTextTShirt = {
size: 'Large'
color: 'yellow'
}
// Esto daría error
Readonly
Readonly
establece que todas las propiedades del genérico recibido sean únicamente de lectura, es decir, no podrán ser modificadas.
interface TShirt {
size: string,
color: string,
frontText?: string,
backText?: string
}
let sampleTShirt: ReadOnly<TShirt> = {
size: 'Medium',
color: 'black'
}
sampleTShirt.color = 'red'
//Esto daría error ya que color no se puede sobrescribir
NonNullable
NonNullable
nos permite tipar eliminando la posibilidad de tener propiedades null
o undefined
en el genérico que recibe.
type TShirtText = string | undefined
type SureTShirtText = NonNullable<TShirtText>
interface FrontAndBackTextTShirt {
size: string,
color: string,
frontText: SureTShirtText,
backText: SureTShirtText
}
const someTShirt:FrontAndBackTextTShirt = {
size: 'Small',
color: 'grey',
frontText: undefined, //Error ya que no puede ser ni null ni undefined
backText: 'something'
}
ReturnType
ReturnType
nos permite obtener el tipo de los datos que devuelve una función.
type BasicTShirt = {
size: string,
color: string
}
function getSampleTShirt(): BasicTShirt {
...some action
}
type SampleTShirt = ReturnType<typeof getSampleTShirt>
// { size: string, color: string }
Awaited
Awaited
extrae el tipo que se resuelve de una promesa que es devuelta por una función.
async function getTShirtsQry(): Promise<TShirt[]> {
...some action
}
type TShirtList = Awaited<typeof getTShirtsQry>;
async function getTShirts(): Promise<void> {
const listOfTShirts: TShirtList = await getTShirtsQry();
// ... some action with this t-shirts
}
Conclusión
En este articulo hemos explorado las Utility Types mas interesantes que tiene TypeScript a día de hoy. Te animo a intentar utilizarlas, te aseguro una vez las tengas dominadas, verás que agilizan tu desarrollo y luego no podrás vivir sin algunas de ellas.
Gracias por tu atención 😊
Gran artículo! Una cosa que he visto: La descripción de Readonly dice “escritura” en vez de ”lectura”
Muchas gracias Carmelo, ya está corregido 🙂