diff --git a/packages/playground-examples/copy/pt/TypeScript/Meta-Types/Conditional Types.ts b/packages/playground-examples/copy/pt/TypeScript/Meta-Types/Conditional Types.ts new file mode 100644 index 000000000000..1b5f34678558 --- /dev/null +++ b/packages/playground-examples/copy/pt/TypeScript/Meta-Types/Conditional Types.ts @@ -0,0 +1,103 @@ +// Tipos Condicionais fornecem uma maneira simples de adicionar +// lógica no sistema de tipos do Typescript. Esse é um recurso +// avançado, e é muito possível que você não precise utilizá-lo +// no seu código do dia a dia. + +// Um tipo condicional se parece com: +// +// A extends B ? C : D +// +// Onde a condição é: se um tipo se extende a uma expressão, +// e que tipo deveria ser retornado. + +// Vamos passar por alguns exemplos, por questões de brevidade +// usaremos apenas uma letra para tipos genéricos. Isso é opcional, +// mas nos restringimos à 60 caracteres para caber na tela. + +type Gato = { miau: true }; +type Cachorro = { latido: true }; +type Guepardo = { miau: true; rapido: true }; +type Lobo = { latido: true; uivos: true }; + +// Podemos criar um tipo condicional onde é possível extrair +// tipos que se aplicam apenas com algo que late. + +type ExtrairLatidos = A extends { latido: true } ? A : never; + +// Assim podemos criar tipos envolvidos pelo ExtrairLatidos: + +// Um gato não late, então iremos retornar never +type GatoNever = ExtrairLatidos; +// Um lobo late, então retornaremos a forma de lobo +type TipoLobo = ExtrairLatidos; + +// Isso se torna útil quando você quer trabalhar com uma união +// de vários tipos e reduzir o número de potenciais opções: + +type Animais = Gato | Cachorro | Guepardo | Lobo; + +// Quando você aplica ExtrairLatidos para um tipo de união, +// é o mesmo que testar a condição com todos os membros do tipo: + +type Latido = ExtrairLatidos; + +// = ExtrairLatidos | ExtrairLatidos | +// ExtrairLatidos | ExtrairLatidos +// +// = never | Cachorro | never | Lobo +// +// = Cachorro | Lobo (veja example:unknown-and-never) + +// Isso é chamado de tipo condicional distributivo porque +// o tipo distribui para cada membro da união. + +// Tipos condicionais diferidos + +// Tipos condicionais podem ser usados para diminuir suas APIs +// que podem retornar diferentes tipos dependendo dos inputs. + +// Por exemplo, essa função pode retornar tanto uma string +// quanto um number dependendo do boolean passado. + +declare function pegarID(legal: T): T extends true ? string : number; + +// Então dependendo do quanto o sistema de tipos sabe sobre o boolean +// você irá receber um tipo de retorno diferente: +let retornoDeString = pegarID(true); +let retornoDeNumber = pegarID(false); +let stringOuNumber = pegarID(Math.random() < 0.5); + +// Nesse caso acima o TypeScript sabe o tipo de retorno imediatamente. +// Contudo, você pode usar tipos condicionais em funções +// onde o tipo não é conhecido. Isso é chamado tipo condicional diferido. + +// O mesmo que o nosso ExtrairLatidos acima, mas como uma função +declare function extrairMiado(x: T): T extends { miau: true } ? T : undefined; + +// Existe uma ferramenta muito útil dentro dos tipos condicionais, na qual +// é possível especificamente dizer ao TypeScript que ele deve inferir o tipo +// quando diferido. Essa é a palavra chave 'infer'. + +// 'infer' é normalmente usado para criar metatipos que inspecionam +// os tipos existentes no seu código, pense nisso como a criação de uma +// nova variável dentro do tipo. + +type PegarOTipoDoRetorno = T extends (...args: any[]) => infer R ? R : T; + +// Brevemente: +// +// - esse é um tipo genérico condicional chamado PegarOTipoDoRetorno +// que recebe um tipo como primeiro parâmetro +// +// - a condição checa se o tipo é uma função, e se for cria um novo tipo +// chamado R baseado no retorno do valor da função +// +// - se a checagem passar, o valor do tipo é inferido como o valor do +// retorno da função, caso contrario é o tipo original +// + +type retornoDoPegarID = PegarOTipoDoRetorno; + +// Isso falha na verifição de ser uma função, e iria apenas retornar o tipo +// passado a ele. +type pegarGato = PegarOTipoDoRetorno; diff --git a/packages/playground-examples/copy/pt/TypeScript/Primitives/Unknown and Never.ts b/packages/playground-examples/copy/pt/TypeScript/Primitives/Unknown and Never.ts new file mode 100644 index 000000000000..024d8ad9edea --- /dev/null +++ b/packages/playground-examples/copy/pt/TypeScript/Primitives/Unknown and Never.ts @@ -0,0 +1,125 @@ +// Unknown + +// Unknown é um daqueles tipos que, assim que você entende, +// acha muitos casos de uso. Ele age como um irmão para o tipo any. +// any permite ambiguidade - unknown requer especificidades. + +// Um bom exemplo poderia envolver um JSON parser. Dados JSON podem vir +// de diferentes formas e o criador da função que analisa o JSON não +// saberá a forma do dado - a pessoa chamando a função deve. + +const transformadorJson = (stringJson: string) => JSON.parse(stringJson); + +const minhaConta = transformadorJson(`{ "nome": "Dorothea" }`); + +minhaConta.nome; +minhaConta.email; + +// Se você passar o mouse em transformadorJson, poderá ver que ele tem +// o tipo de retorno any, assim como o minhaConta. É possível ajustar isso +// com tipos Genéricos - mas também é possível ajustar isso com o unkown. + +const transformadorJsonUnkown = (stringJson: string): unknown => JSON.parse(stringJson); + +const minhaOutraConta = transformadorJsonUnkown(`{ "nome": "Samuel" }`); + +minhaOutraConta.nome; + +// O objeto minhaOutraConta não pode ser usado até o tipo ser declarado +// para o TypeScript. Isso pode ser usado para garantir que +// quem consumir a API pense em sua tipagem com antecedência: + +type Usuario = { nome: string }; +const minhaContaDeUsuario = transformadorJsonUnkown(`{ "nome": "Samuel" }`) as Usuario; +minhaContaDeUsuario.nome; + +// Unknown é uma boa ferramenta, para entendê-lo ainda mais leia: +// https://mariusschulz.com/blog/the-unknown-type-in-typescript +// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type + +// Never + +// Como o Typescript suporta análise de fluxo do código, a linguagem +// precisa ser capaz de representar quando lógicamente o código não pode +// acontecer. Por exemplo, essa função não pode retornar: + +const nuncaRetorna = () => { + // Se for lançado um erro na primeira linha + throw new Error("Sempre lança um erro, nunca retorna"); +}; + +// Se você passar o mouse em cima da função, verá () => never +// que significa que isso nunca deverá acontecer. Estes ainda +// podem ser passados como outros valores: + +const meuValor = nuncaRetorna(); + +// Tendo uma função que retorna never pode ser útil quando lidamos com +// a imprevisiblidade do runtime JavaScript e os +// consumidores da API que podem não estar usando tipos: + +const validarUsuario = (usuario: Usuario) => { + if (usuario) { + return usuario.nome !== "NaN"; + } + + // De acordo com o sistema de tipos, esse caminho do código + // nunca deveria acontecer, que combina com o tipo de + // retorno do nuncaRetorna. + + return nuncaRetorna(); +}; + +// O estado da definição de tipos indica que um usuário deve ser +// passado, mas existem muitas válvulas de escape no JavaScript +// por meio das quais você não pode garantir isso. + +// Usar uma função que retorna never te permite adicionar +// código em partes que não deveriam ser possíveis. +// Isso é útil para mostrar uma mensagem de erro melhor, +// ou fechar recursos como arquivos ou loops. + +// Um tipo de uso bem popular para o never é garantir que um +// switch é exaustivo. Por exemplo, todos os caminhos são cobertos. + +// Aqui tem um enum e um switch exaustivo, tente adicionar +// uma nova opção para o enum (talvez Tulipa?) + +enum Flor { + Rosa, + Rododendro, + Violeta, + Margarida, +} + +const nomeDaFlorEmLatim = (flor: Flor) => { + switch (flor) { + case Flor.Rosa: + return "Rosa rubiginosa"; + case Flor.Rododendro: + return "Rhododendron ferrugineum"; + case Flor.Violeta: + return "Viola reichenbachiana"; + case Flor.Margarida: + return "Bellis perennis"; + + default: + const _checagemExaustiva: never = flor; + return _checagemExaustiva; + } +}; + +// Você vai ter um erro de compilação falando que seu +// novo tipo de flor não pode ser convertido em never. + +// Never em Unions + +// O never é removido automaticamente do tipo union. + +type NeverERemovido = string | never | number; + +// Se você olhar no tipo para NeverERemovido, verá que +// é string | number. Isso é porque never nunca deve acontecer em +// tempo de execução, já que você não pode atribuir a ele. + +// Esse recurso é muito utilizado em example:conditional-types