TypeScript: Os 5 mandamentos ao usar TypeScript

Mais e mais projetos e equipes estão adotando o TypeScript. No entanto, há uma enorme diferença entre usar o TypeScript e tirar o máximo proveito dele.

Apresento a você esta lista de práticas de alto nível recomendadas para TypeScript que ajudarão você a aproveitar ao máximo suas funcionalidades.

Este artigo também está disponível em russo: 5 заповедей TypeScript-разработчика (por Vadim Belorussov).

Não minta

Tipos são um contrato. O que isso significa? Quando você implementa uma função, seu tipo é uma promessa para outros desenvolvedores (ou para você no futuro)!

No exemplo a seguir, o tipo da promessa retornará um objeto que sempre terá duas propriedades: e .

interface User {
name: string;
age: number;
}
function getUser(id: number): User { /* ... */ }

TypeScript é uma linguagem muito flexível. Está cheio de suposições feitas para facilitar sua adoção. Por exemplo, TypeScript permite implementar assim:

function getUser(id: number): User {
return { age: 12 } as User;
}

Não faça isso! Isso é mentira. Ao fazer isso, você mente para outros desenvolvedores também (que usarão essa função em suas funções). Eles esperam que o objeto retornado em sempre tenha algum . Mas isso não acontece! Então, o que acontece quando seu companheiro de equipe escreve ? Você conhece bem...

Claro, essa mentira parece muito óbvia. No entanto, ao trabalhar com uma enorme base de código, você geralmente se encontra em uma situação em que um valor que deseja retornar (ou passar) quase corresponde ao tipo esperado. Descobrir o motivo da incompatibilidade de tipos leva tempo e esforço e você está com pressa … então decide fazer utilizar type casting com .

No entanto, ao fazer isso, você viola o contrato, que é sagrado! É sempre melhor dedicar um tempo para descobrir por que os tipos não combinam do que para fazer type casting. É muito provável que algum bug em tempo de execução esteja oculto sob a superfície.

Não minta. Respeite seus contratos.

Seja preciso

Tipos são documentação. Quando você documenta uma função, não deseja transmitir o máximo de informação possível?

// Retorna um objeto
function getUser(id) { /* ... */ }
// Retorna um objeto com duas propriedades: name e age
function getUser(id) { /* ... */ }
// Se id for um número e um usuário com esse id existe,
// retorna um objeto com duas propriedades: name e age
// Caso contrário, retorna undefined
function getUser(id) { /* ... */ }

Qual comentário em você prefere? Quanto mais você souber sobre o que a função retorna, melhor. Por exemplo, sabendo que poderia retornar undefined, você pode escrever uma instrução para verificar se o valor retornado está definido antes de acessar suas propriedades.

É exatamente o mesmo com os tipos. Quanto mais preciso for um tipo, mais informações ele transmite.

function getUserType(id: number): string { /* ... */ }function getUserType(id: number): 'standard' | 'premium' | 'admin' { /* ... */ }

A segunda versão do é muito mais informativa e, portanto, coloca o chamador em uma situação muito melhor. É mais fácil manipular um valor se você souber o que ele é com toda a certeza (contratos, lembra?), uma das três strings, ao invés de saber que ele pode ser qualquer string. Para iniciantes, você tem certeza de que o valor não é uma sequência vazia.

Vamos ver um exemplo mais realista. O tipo representa o estado de um componente que busca alguns dados do back-end. Esse tipo é preciso?

interface State {
isLoading: boolean;
data?: string[];
errorMessage?: string;
}

O consumidor desse tipo deve lidar com algumas combinações improváveis ​​de valores de propriedade. Por exemplo, não é possível que ambos e sejam definidos (a busca de dados pode ser bem-sucedida ou resultar em um erro).

Podemos tornar um tipo muito mais preciso com a ajuda de tipos de união discriminados:

type State =
| { status: 'loading' }
| { status: 'successful', data: string[] }
| { status: 'failed', errorMessage: string };

Agora, o consumidor desse tipo tem muito mais informações. Eles não precisam lidar com combinações ilegais de valores de propriedades.

Seja preciso. Transmita o máximo de informações possível em seus tipos!

Comece com tipos

Como os tipos são contrato e documentação, eles são ótimos para projetar suas funções (ou métodos).

Existem muitos artigos na Internet que aconselham os engenheiros de software a pensar antes de escreverem o código . Eu concordo totalmente com essa abordagem. É tentador pular direto para o código, mas geralmente leva a algumas decisões ruins. Passar algum tempo pensando na implementação sempre compensa.

Os tipos são super úteis nesse processo. Pensar pode resultar na anotação das assinaturas de tipo das funções envolvidas na sua solução. É incrível porque permite que você se concentre no que suas funções fazem, ao invés de como elas fazem.

O React.js tem um conceito de componentes de ordem superior. São funções que aumentam determinado componente de alguma maneira. Por exemplo, você pode criar um componente que adiciona um indicador de carregamento a um componente existente.

Vamos escrever a assinatura de tipo para esta função. Ele pega um componente e retorna um componente. Podemos usar o React para indicar um componente.

é um tipo genérico parametrizado pelo tipo de propriedades do componente. pega um componente e retorna um novo componente que mostra o componente original ou mostra um indicador de carregamento. A decisão é tomada com base no valor de uma nova propriedade booleana . Portanto, o componente resultante deve exigir as mesmas propriedades que o componente original mais a nova propriedade.

Vamos finalizar o tipo. pega um componente de um tipo em que denota o tipo das propriedades. Retorna um componente com propriedades aumentadas do tipo .

const withLoadingIndicator = <P>(Component: ComponentType<P>) 
: ComponentType<P & { isLoading: boolean }> =>
({ isLoading, ...props }) => { /* ... */ }

Descobrir o tipo dessa função nos forçou a pensar sobre sua entrada e saída. Em outras palavras, nos fez projetá-la. Escrever a implementação é um pedaço de bolo agora.

Comece com tipos. Deixe os tipos forçarem você a projetar antes de implementar.

Abrace o rigor

Os três primeiros pontos exigem que você preste muita atenção nos tipos. Felizmente, você não está sozinho na tarefa — o compilador TypeScript geralmente informa quando seus tipos estão ou quando não são precisos o suficiente.

Você pode tornar o compilador ainda mais útil ativando o sinalizador do compilador. É uma bandeira meta que permite que todas as opções estritas verificação de tipo: , , , , , e .

O que eles fazem? Em geral, habilitá-los resulta em mais erros do compilador TypeScript. Isso é bom! Mais erros do compilador significam mais ajuda do compilador.

Vamos ver como a ativação ajuda a identificar algumas mentiras.

function getUser(id: number): User {
if (id >= 0) {
return { name: 'John', age: 12 };
} else {
return undefined;
}
}

O tipo de diz que sempre retornará um . No entanto, como você pode ver na implementação, ele também pode retornar um valor !

Felizmente, ativando retorna um erro do compilador:

Type 'undefined' is not assignable to type 'User'.

O compilador TypeScript detectou a mentira. Você pode se livrar do erro dizendo a verdade:

function getUser(id: number): User | undefined { /* ... */ }

Abrace o tipo de verificação da rigidez. Deixe o compilador observar seus passos.

Mantenha-se atualizado

A linguagem TypeScript está sendo desenvolvida em um ritmo muito rápido. Há um novo lançamento a cada dois meses. Cada versão traz melhorias significativas no idioma e novos recursos.

Geralmente, os novos recursos de idioma permitem tipos mais precisos e uma verificação mais rigorosa.

Por exemplo, a versão 2.0 introduziu Tipos de União Discriminada (que eu mencionei no tópico Seja preciso).

Versão 3.2 introduziu a opção do compilador que permite a digitação correta das funções , e .

A versão 3.4 melhorou a inferência de tipo em funções de ordem superior, facilitando o uso de tipos precisos ao escrever código em estilo funcional.

O que quero dizer aqui é que realmente vale a pena conhecer os recursos de linguagem introduzidos nas versões mais recentes do TypeScript. Eles geralmente podem ajudá-lo a aderir aos outros quatro mandamentos desta lista.

Um bom ponto de partida é o roteiro oficial do TypeScript. Também é uma boa idéia verificar a seção TypeScript do Microsoft Devblog regularmente, pois todos os anúncios de lançamento são feitos por lá.

Mantenha-se atualizado com os novos recursos de idioma e deixe a linguagem fazer o trabalho para você.

Finalizando

Espero que você ache essa lista útil. Como qualquer coisa na vida, esses mandamentos não devem ser seguidos cegamente. No entanto, acredito firmemente que essas regras o tornarão um programador TypeScript melhor.

Eu adoraria ouvir sua opinião sobre isso na seção de comentários.

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store