No dia 20 de Agosto de 2020, o TypeScript anunciou a sua mais nova versão, a 4.0! Então, neste artigo, me preparei para apresentar para vocês as últimas mudanças e novidades da versão!

Apesar de ser uma major version as alterações que foram introduzidas nesse release não são muito substanciais e, pode se acalmar, não temos nenhuma breaking change :D

Tuplas nomeadas

Para começar, temos a resolução de um problema relativamente antigo do superset mais amado por todos. Quando temos tuplas (elementos que são compostos de pares de dados), antigamente tínhamos uma definição como esta:

function tupla (...args: [string, number]) {}

Veja que não temos nenhum nome para nenhum dos parâmetros que ocupam tanto a posição da string quanto a posição do number. No que diz respeito à inferência de tipos e à checagem no geral, isso não faz diferença alguma, mas é muito útil quando estamos documentando nosso código.

Por conta da checagem de tipos, a função anterior seria traduzida para algo semelhante a isto:

function tupla (args_0: string, args_1: number) {}

Que é essencialmente a mesma coisa, porém, na hora de fazermos o código, o nosso intellisense – que é uma das grandes vantagens do uso do TypeScript, no geral – vai nos dar uma nomenclatura que não ajuda ninguém, como podemos ver no gif abaixo

Nomenclatura como args_0 e args_1

Agora, com a versão 4.0, podemos incluir nomes nas nossas tuplas para que elas sejam nomeadas durante o intellisense:

function tupla (...args: [nome: string, idade: number]) {}

E ai conseguimos um resultado como o seguinte:

Conseguimos ver a nomenclatura de cada parâmetro

É importante notar que: Se você está nomeando qualquer elemento de uma tupla, você precisa nomear os dois. Caso contrário você terá um erro:

type Segment = [first: string, number];
//                             ~~~~~~
// error! Tuple members must all have names or all not have names.

Inferência de propriedades a partir do construtor

A partir de agora, quando configuramos o TypeScript com a configuração noImplicitAny, podemos usar a análise de fluxo que é feita no tempo de compilação para determinar os tipos de propriedades em classes de acordo com as atribuições em seu construtor.

class Test {    
   public x   
   constructor (b: boolean){      
     this.x = 42
     if (b) this.x = 'olá'
   }
}

Em versões anteriores, como não estamos especificando o tipo da propriedade, isto faria o compilador atribuir o tipo any, mas como checamos que não queremos any de forma implícita, então o compilador nos daria um erro dizendo que não podemos ter nenhum tipo de any implícito.

Na versão mais atual, o TypeScript consegue inferir, a partir do construtor, que x é do tipo string | number.

Short-Circuit em operadores compostos

Poucas pessoas conhecem esta funcionalidade do JavaScript, mas muitas outras linguagens também possuem o que é chamado de compound assignment operator, ou, operadores de atribuição compostos.

O que eles fazem é resolver a expressão do lado direito e atribuir o valor para a variável do lado esquerdo. Os mais famosos são os operadores algébricos:

let b += 2
let c /= 3

Todos funcionam muito bem e existem para a maioria das operações lógicas. Porém, de acordo com o próprio time do TS, existem três notáveis exceções à esta regra. Os operadores lógicos &&, || e o operador de coalescencia nula ??. No 4.0 temos a adição de três novos operadores:

a ||= b
// que é igual a
a || (a = b)

Além disso temos os operadores &&= e ??=.

Catch com unknown

Desde os primórdios do TypeScript, sempre que tínhamos uma cláusula catch, o valor do argumento de erro era sempre definido como any, pois não havia como saber qual era o tipo de retorno.

Portanto, o TypeScript simplesmente não checava os tipos destes parâmetros, mesmo se o noImplicitAny estava ativo.

try {
  throw 'Alguma coisa'
} catch (err) { // Este 'err' é Any
  console.log(err.foo()) // não vai dar erro
}

Isso era pouco seguro uma vez que podíamos chamar qualquer função dentro do catch. A partir do 4.0, o TS vai tipar os erros como unknown.

O tipo unknown é um tipo especificamente voltado para tipar coisas que não sabemos o que são. Portanto elas precisam de um type-casting antes de poderem ser usadas. É como se um dado do tipo unknown fosse um papel em branco e você pudesse pinta-lo da cor que quiser. Neste caso, o unknown pode ser convertido para qualquer tipo.

Outras mudanças

Além de mudanças na linguagem, a velocidade de compilação com a flag --noEmitOnError ficou mais rápida quando usamos junto com a flag --incremental. O que a última flag faz é dar a possibilidade de compilarmos uma aplicação mais rapidamente a partir de uma outra aplicação que já foi compilada, a chamada compilação incremental.

Quando utilizávamos --incremental com --noEmitOnError, se compilássemos um programa pela primeira vez e ele der um erro, isso significa que ele não emitira nenhuma saída, portanto não há um arquivo .tsbuildinfo onde o --incremental poderá olhar, o que tornava tudo super devagar.

Na versão 4.0 este problema foi corrigido. E, além disso, agora é permitido o uso da flag --noEmit juntamente com --incremental, o que não era permitido antes pois --incremental precisava da emissão de um .tsbuildinfo.

Algumas outras mudanças menores foram feitas no que diz respeito à edição e editores no geral. Você pode conferir a postagem do blog aqui.

Conclusão

E fechamos por aqui a nossa atualização deste superset sensacional! Lembrando que estamos precisando de ajuda na tradução para português no site do TypeScript, nos ajude a traduzir!

Não se esqueça de se inscrever na newsletter para mais conteúdo exclusivo e notícias semanais! Curta e compartilhe seus feedbacks nos comentários!