Hoja de referencia de tipos avanzados de TypeScript (con ejemplos)

TypeScript es un lenguaje escrito que le permite especificar el tipo de variables, parámetros de función, valores devueltos y propiedades del objeto.

Aquí una hoja de trucos avanzada de tipos de TypeScript con ejemplos.

Vamos a sumergirnos.

  • Tipos de intersección
  • Tipos de unión
  • Tipos genéricos
  • Tipos de utilidad
  • Parcial
  • Necesario
  • Solo lectura
  • Recoger
  • Omitir
  • Extraer
  • Excluir
  • Grabar
  • No anulable
  • Tipos mapeados
  • Guardias de tipo
  • Tipos condicionales

Tipos de intersección

Un tipo de intersección es una forma de combinar varios tipos en uno. Esto significa que puede fusionar un tipo A determinado con un tipo B o más y obtener un solo tipo con todas las propiedades.

type LeftType = { id: number left: string } type RightType = { id: number right: string } type IntersectionType = LeftType & RightType function showType(args: IntersectionType) { console.log(args) } showType({ id: 1, left: "test", right: "test" }) // Output: {id: 1, left: "test", right: "test"} 

Como se puede ver, IntersectionTypecombina dos tipos - LeftTypey RightTypey utiliza la &señal para construir el tipo de intersección.

Tipos de unión

Los tipos de unión le permiten tener diferentes tipos de anotaciones dentro de una variable dada.

type UnionType = string | number function showType(arg: UnionType) { console.log(arg) } showType("test") // Output: test showType(7) // Output: 7 

La función showTypees un tipo de unión que acepta tanto cadenas como números como parámetro.

Tipos genéricos

Un tipo genérico es una forma de reutilizar parte de un tipo determinado. Ayuda a capturar el tipo Tpasado como parámetro.

function showType(args: T) { console.log(args) } showType("test") // Output: "test" showType(1) // Output: 1 

Para construir un tipo genérico, debe usar los corchetes y pasar Tcomo parámetro.

Aquí, utilizo T(el nombre depende de usted) y luego, llamo a la función showTypedos veces con anotaciones de tipo diferente porque es genérica, se puede reutilizar.

interface GenericType { id: number name: T } function showType(args: GenericType) { console.log(args) } showType({ id: 1, name: "test" }) // Output: {id: 1, name: "test"} function showTypeTwo(args: GenericType) { console.log(args) } showTypeTwo({ id: 1, name: 4 }) // Output: {id: 1, name: 4} 

Aquí, tenemos otro ejemplo que tiene una interfaz GenericTypeque recibe un tipo genérico T. Y como es reutilizable, podemos llamarlo primero con una cadena y luego con un número.

interface GenericType { id: T name: U } function showType(args: GenericType) { console.log(args) } showType({ id: 1, name: "test" }) // Output: {id: 1, name: "test"} function showTypeTwo(args: GenericType) { console.log(args) } showTypeTwo({ id: "001", name: ["This", "is", "a", "Test"] }) // Output: {id: "001", name: Array["This", "is", "a", "Test"]} 

Un tipo genérico puede recibir varios argumentos. Aquí, pasamos dos parámetros: Ty U, y luego los usamos como anotaciones de tipo para las propiedades. Dicho esto, ahora podemos usar la interfaz y proporcionar diferentes tipos como argumentos.

Tipos de utilidad

TypeScript proporciona útiles utilidades integradas que ayudan a manipular tipos fácilmente. Para usarlos, debe pasar al tipo que desea transformar.

Parcial

  • Partial

Parcial le permite hacer que todas las propiedades del tipo sean Topcionales. Agregará una ?marca al lado de cada campo.

interface PartialType { id: number firstName: string lastName: string } function showType(args: Partial) { console.log(args) } showType({ id: 1 }) // Output: {id: 1} showType({ firstName: "John", lastName: "Doe" }) // Output: {firstName: "John", lastName: "Doe"} 

Como puede ver, tenemos una interfaz PartialTypeque se usa como anotación de tipo para los parámetros que recibe la función showType(). Y para que las propiedades sean opcionales, tenemos que usar la Partialpalabra clave y pasar el tipo PartialTypecomo argumento. Dicho esto, ahora todos los campos se vuelven opcionales.

Necesario

  • Required

A diferencia Partial, la Requiredutilidad hace que todas las propiedades del tipo sean Tnecesarias.

interface RequiredType { id: number firstName?: string lastName?: string } function showType(args: Required) { console.log(args) } showType({ id: 1, firstName: "John", lastName: "Doe" }) // Output: { id: 1, firstName: "John", lastName: "Doe" } showType({ id: 1 }) // Error: Type '{ id: number: }' is missing the following properties from type 'Required': firstName, lastName 

La Requiredutilidad hará que todas las propiedades sean requeridas incluso si las hacemos opcionales primero antes de usar la utilidad. Y si se omite una propiedad, TypeScript arrojará un error.

Solo lectura

  • Readonly

Este tipo de utilidad transformará todas las propiedades del tipo Tpara que no sean reasignables con un nuevo valor.

interface ReadonlyType { id: number name: string } function showType(args: Readonly) { args.id = 4 console.log(args) } showType({ id: 1, name: "Doe" }) // Error: Cannot assign to 'id' because it is a read-only property. 

Aquí, usamos la utilidad Readonlypara hacer que las propiedades de ReadonlyTypeno sean reasignables. Dicho esto, si intenta dar un nuevo valor a uno de estos campos, se producirá un error.

Además de eso, también puede utilizar la palabra clave readonlydelante de una propiedad para que no sea reasignable.

interface ReadonlyType { readonly id: number name: string } 

Recoger

  • Pick

Le permite crear un nuevo tipo a partir de un modelo existente Tseleccionando algunas propiedades Kde ese tipo.

interface PickType { id: number firstName: string lastName: string } function showType(args: Pick) { console.log(args) } showType({ firstName: "John", lastName: "Doe" }) // Output: {firstName: "John"} showType({ id: 3 }) // Error: Object literal may only specify known properties, and 'id' does not exist in type 'Pick' 

Pickes un poco diferente de las utilidades anteriores que ya hemos visto. Espera dos parámetros: Tes el tipo del que desea elegir elementos y Kes la propiedad que desea seleccionar. También puede seleccionar varios campos separándolos con un |símbolo de barra vertical ( ).

Omitir

  • Omit

The Omit utility is the opposite of the Pick type. And instead of selecting elements, it will remove K properties from the type T.

interface PickType { id: number firstName: string lastName: string } function showType(args: Omit) { console.log(args) } showType({ id: 7 }) // Output: {id: 7} showType({ firstName: "John" }) // Error: Object literal may only specify known properties, and 'firstName' does not exist in type 'Pick' 

This utility is similar to the way Pick works. It expects the type and the properties to omit from that type.

Extract

  • Extract

Extract allows you to construct a type by picking properties that are present in two different types. The utility will extract from T all properties that are assignable to U.

interface FirstType { id: number firstName: string lastName: string } interface SecondType { id: number address: string city: string } type ExtractType = Extract // Output: "id" 

Here, we have two types that have in common the property id. And hence by using the Extract keyword, we get back the field id since it's present in both interfaces. And if you have more than one shared field, the utility will extract all similar properties.

Exclude

Unlike Extract, the Exclude utility will construct a type by excluding properties that are already present in two different types. It excludes from T all fields that are assignable to U.

interface FirstType { id: number firstName: string lastName: string } interface SecondType { id: number address: string city: string } type ExcludeType = Exclude // Output; "firstName" | "lastName" 

As you can see here, the properties firstName and lastName are assignable to the SecondType type since they are not present there. And by using the Extract keyword, we get back these fields as expected.

Record

  • Record

This utility helps you to construct a type with a set of properties K of a given type T. Record is really handy when it comes to mapping the properties of a type to another one.

interface EmployeeType { id: number fullname: string role: string } let employees: Record = { 0: { id: 1, fullname: "John Doe", role: "Designer" }, 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" }, 2: { id: 3, fullname: "Sara Duckson", role: "Developer" }, } // 0: { id: 1, fullname: "John Doe", role: "Designer" }, // 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" }, // 2: { id: 3, fullname: "Sara Duckson", role: "Developer" } 

The way Record works is relatively simple. Here, it expects a number as a type which is why we have 0, 1, and 2 as keys for the employees variable. And if you try to use a string as a property, an error will be thrown. Next, the set of properties is given by EmployeeType hence the object with the fields id, fullName, and role.

NonNullable

  • NonNullable

It allows you to remove null and undefined from the type T.

type NonNullableType = string | number | null | undefined function showType(args: NonNullable) { console.log(args) } showType("test") // Output: "test" showType(1) // Output: 1 showType(null) // Error: Argument of type 'null' is not assignable to parameter of type 'string | number'. showType(undefined) // Error: Argument of type 'undefined' is not assignable to parameter of type 'string | number'. 

Here, we pass the type NonNullableType as an argument to the NonNullable utility which constructs a new type by excluding null and undefined from that type. That said, if you pass a nullable value, TypeScript will throw an error.

By the way, if you add the --strictNullChecks flag to the tsconfig file, TypeScript will apply non-nullability rules.

Mapped types

Mapped types allow you to take an existing model and transform each of its properties into a new type. Note that some utility types covered earlier are also mapped types.

type StringMap = { [P in keyof T]: string } function showType(arg: StringMap) { console.log(arg) } showType({ id: 1, name: "Test" }) // Error: Type 'number' is not assignable to type 'string'. showType({ id: "testId", name: "This is a Test" }) // Output: {id: "testId", name: "This is a Test"} 

StringMap will transform whatever types that passed in into a string. That said, if we use it in the function showType(), the parameters received must be a string - otherwise, an error will be thrown by TypeScript.

Type Guards

Type Guards allow you to check the type of a variable or an object with an operator. It's a conditional block that returns a type using typeof, instanceof, or in.

  • typeof
function showType(x: number | string) { if (typeof x === "number") { return `The result is ${x + x}` } throw new Error(`This operation can't be done on a ${typeof x}`) } showType("I'm not a number") // Error: This operation can't be done on a string showType(7) // Output: The result is 14 

As you can see, we have a normal JavaScript conditional block that checks the type of the argument received with typeof. With that in place, you can now guard your type with this condition.

  • instanceof
class Foo { bar() { return "Hello World" } } class Bar { baz = "123" } function showType(arg: Foo | Bar) { if (arg instanceof Foo) { console.log(arg.bar()) return arg.bar() } throw new Error("The type is not supported") } showType(new Foo()) // Output: Hello World showType(new Bar()) // Error: The type is not supported 

Like the previous example, this one is also a type guard that checks if the parameter received is part of the Foo class or not and handles it consequently.

  • in
interface FirstType { x: number } interface SecondType { y: string } function showType(arg: FirstType | SecondType) { if ("x" in arg) { console.log(`The property ${arg.x} exists`) return `The property ${arg.x} exists` } throw new Error("This type is not expected") } showType({ x: 7 }) // Output: The property 7 exists showType({ y: "ccc" }) // Error: This type is not expected 

The in operator allows you to check whether a property x exists or not on the object received as a parameter.

Conditional Types

Conditional types test two types and select one of them depending on the outcome of that test.

type NonNullable = T extends null | undefined ? never : T 

This example of the NonNullable utility type checks if the type is null or not and handle it depending on that. And as you can note, it uses the JavaScript ternary operator.

Thanks for reading.

You can find other great content like this on my blog or follow me on Twitter to get notified.