Folha de dicas de tipos avançados de TypeScript (com exemplos)

TypeScript é uma linguagem digitada que permite especificar o tipo de variáveis, parâmetros de função, valores retornados e propriedades do objeto.

Aqui está uma folha de dicas de Tipos TypeScript avançada com exemplos.

Vamos mergulhar.

  • Tipos de interseção
  • Tipos de União
  • Tipos Genéricos
  • Tipos de utilidades
  • Parcial
  • Requeridos
  • Somente leitura
  • Escolher
  • Omitir
  • Extrair
  • Excluir
  • Registro
  • Não anulável
  • Tipos mapeados
  • Protetores de Tipo
  • Tipos condicionais

Tipos de interseção

Um tipo de interseção é uma forma de combinar vários tipos em um. Isso significa que você pode mesclar um determinado tipo A com um tipo B ou mais e obter um único tipo com todas as propriedades.

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 você pode ver, IntersectionTypecombina dois tipos - LeftTypee RightTypee usa o &sinal para construir o tipo de cruzamento.

Tipos de União

Os tipos de união permitem que você tenha diferentes tipos de anotação em uma determinada variável.

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

A função showTypeé um tipo de união que aceita strings e números como parâmetro.

Tipos Genéricos

Um tipo genérico é uma forma de reutilizar parte de um determinado tipo. Ajuda a capturar o tipo Tpassado como parâmetro.

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

Para construir um tipo genérico, você precisa usar os colchetes e passar Tcomo parâmetro.

Aqui, eu uso T(o nome é com você) e, em seguida, chamo a função showTypeduas vezes com anotações de tipo diferente porque é genérico - pode ser reutilizado.

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} 

Aqui, temos outro exemplo que possui uma interface GenericTypeque recebe um tipo genérico T. E como é reutilizável, podemos chamá-lo primeiro com uma string e depois com um 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"]} 

Um tipo genérico pode receber vários argumentos. Aqui, passamos dois parâmetros: Te U, e então os usamos como anotações de tipo para as propriedades. Dito isso, agora podemos usar a interface e fornecer diferentes tipos como argumentos.

Tipos de utilidades

O TypeScript fornece utilitários internos úteis que ajudam a manipular os tipos facilmente. Para usá-los, você precisa passar para o tipo que deseja transformar.

Parcial

  • Partial

Parcial permite que você torne todas as propriedades do tipo Topcionais. Isso adicionará uma ?marca ao 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 você pode ver, temos uma interface PartialTypeque serve como anotação de tipo para os parâmetros recebidos pela função showType(). E para tornar as propriedades opcionais, temos que usar a Partialpalavra - chave e passar o tipo PartialTypecomo um argumento. Dito isso, agora todos os campos se tornam opcionais.

Requeridos

  • Required

Ao contrário Partial, o Requiredutilitário torna todas as propriedades do tipo Tnecessárias.

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 

O Requiredutilitário tornará todas as propriedades obrigatórias, mesmo que as tornemos opcionais antes de usar o utilitário. E se uma propriedade for omitida, o TypeScript lançará um erro.

Somente leitura

  • Readonly

Este tipo de utilitário transformará todas as propriedades do tipo Tpara torná-las não reatribuíveis com um novo 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. 

Aqui, usamos o utilitário Readonlypara tornar as propriedades ReadonlyTypenão reatribuíveis. Dito isso, se você tentar dar um novo valor a um desses campos, um erro será gerado.

Além disso, você também pode usar a palavra-chave readonlyna frente de uma propriedade para torná-la não reatribuível.

interface ReadonlyType { readonly id: number name: string } 

Escolher

  • Pick

Ele permite que você crie um novo tipo a partir de um modelo existente T, selecionando algumas propriedades Kdesse 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' 

Pické um pouco diferente dos utilitários anteriores que já vimos. Ele espera dois parâmetros - Té o tipo do qual você deseja selecionar os elementos e Ké a propriedade que deseja selecionar. Você também pode escolher vários campos, separando-os com um |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 

Como o exemplo anterior, este também é um protetor de tipo que verifica se o parâmetro recebido faz parte da Fooclasse ou não e o manipula conseqüentemente.

  • 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 

O inoperador permite verificar se uma propriedade xexiste ou não no objeto recebido como parâmetro.

Tipos condicionais

Os tipos condicionais testam dois tipos e selecionam um deles dependendo do resultado desse teste.

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

Este exemplo do NonNullabletipo de utilitário verifica se o tipo é nulo ou não e o manipula dependendo disso. E, como você pode notar, ele usa o operador ternário JavaScript.

Obrigado pela leitura.

Você pode encontrar outros conteúdos excelentes como este no meu blog ou me seguir no Twitter para ser notificado.