O que há de novo no beta do TypeScript 4.3

A nova versão do TypeScript saiu em beta no dia 1 de abril de 2021! Por enquanto essa versão ainda não está pronta para ser utilizada em produção, mas ela já inclui algumas mudanças e correções super legais!

Para testar isso tudo você pode instalar a versão mais nova com npm i typescript@beta e sair usufruindo das novas funcionalidades!

Tipos de escrita e leitura separados

Originalmente quando temos algum tipo de propriedade em uma classe que pode ser escrita e lida de formas diferentes, fazemos um getter e um setter para essa propriedade, por exemplo:

class Foo {
    #prop = 0
    
    get prop() {
        return this.#prop
    }

	set prop (value) {
        let val = Number(value)
        if (!Number.isFinite(num)) return
        this.#prop = val
    }
}

No TypeScript, por padrão, o tipo é inferido a partir do tipo de retorno no get, o problema é que, se tivermos uma propriedade set que pode ser setada de várias formas, por exemplo, como uma string ou number, o tipo de retorno desta propriedade será inferido como unknown ou any.

O problema disso é que, quando estamos utilizando unknown, forçamos um cast para o tipo que queremos, e any realmente não faz nada. Esse modelo nos forçava a tomar uma escolha entre ser preciso ou permissivo. No TS 4.3 podemos especificar tipos separados para entrada e saída das propriedades:

class Foo {
    private prop = 0
    
    get prop(): number {
        return this.prop
    }

	set prop (value: string | number) {
        let val = Number(value)
        if (!Number.isFinite(num)) return
        this.prop = val
    }
}

E isso não é limitado apenas às classes, podemos fazer a mesma coisa com objetos literais:

function buildFoo (): Foo {
  let prop = 0
  return {
    get prop(): number { return prop }
    set prop(value: string | number) {
      let val = Number(value)
      if (!Number.isfinite(val) return
      prop = val
    }
  }
}

E isso também vale para interfaces:

interface Foo {
  get prop (): number
  set prop (value: string | number)
}

A única limitação que temos aqui é que o método set precisa ter na sua lista de tipos o mesmo tipo do get, ou seja, se temos um getter que retorna um number o setter precisa aceitar um number.

Keyword override

Uma mudança menos comum mas igualmente importante vem quando temos classes derivadas. Geralmente, quando usamos uma classe derivada com extends, temos vários métodos da classe pai que precisam ser sobrescritos, ou então adaptados. Para isso nós escrevemos um método na classe derivada com a mesma assinatura:

class Pai {
  metodo (value: boolean) { }
  outroMetodo (value: number) {}
}

classe Filha extends Pai {
  metodo () { }
  outroMetodo () { }
}

O que acontece é que estamos sobrescrevendo os dois métodos da classe pai e utilizando somente os da classe derivada. Porém, se modificarmos a classe pai e removermos os dois métodos em favor de um único método, assim:

class Pai {
  metodoUnico (value: boolean) { }
}

classe Filha extends Pai {
  metodo () { }
  outroMetodo () { }
}

O que acontece é que nossa classe filha não vai sobrescrever mais o método da classe pai e, portanto, vai ter dois métodos completamente inúteis que nunca serão chamados.

Por conta disso, o TypeScript 4.3 adicionou uma nova keyword chamada override. O que esta keyword faz é informar o servidor que um método da classe filha está sendo explicitamente sobrescrito, então podemos fazer desta forma:

class Pai {
  metodo () { }
  outroMetodo () { }
}

classe Filha extends Pai {
  override metodo () { }
  override outroMetodo () { }
}

Neste exemplo estamos dizendo para o TypeScript procurar explicitamente na classe pai se existem dois métodos com estes nomes. E ai se modificarmos a nossa classe pai e mantermos a classe filha:

class Pai {
  metodoUnico (value: boolean) { }
}
classe Filha extends Pai {
  override metodo () { }
  override outroMetodo () { }
}

// Error! This method can't be marked with 'override' because it's not declared in 'Pai'.

Além disso uma nova flag --noImplicitOverride foi adicionada para evitar que esqueçamos de fazer essa identificação. Quando isso acontecer não vamos poder sobrescrever algum método sem escrever override antes e, todos os métodos não marcados, não serão estendidos.

Auto Imports

A última atualização importante que vamos comentar é mais sobre uma melhoria significativa de vida para todos que escrevem imports (que é, basicamente, todo mundo). Antes, quando escrevíamos `import {` o TypeScript não tinha como saber o que íamos importar, então frequentemente escrevíamos `import {} from 'modulo.ts'` e depois voltávamos aos `{}` para poder usar o autocomplete no que sobrou.


Na versão 4.3, vamos ter a inteligência dos auto-imports que já existem no editor para poder completar as nossas declarações, como o vídeo mostra:

Animação com os detalhes do autoimport para completar a declaração d emódulos importador no TypeScript

A parte importante aqui é que precisamos que o editor suporte essa funcionalidade, por enquanto ela está disponível na versão 1.56 do VSCode normal, mas somente com a extensão do TS/JS nightly instalada.

Outras atualizações

Além das atualizações que comentamos, o TypeScript também modificou e melhorou bastante a forma como os templete literal types são inferidos e identificados. Agora podemos utilizar eles de uma maneira muito mais simples e direta.

Também temos melhores asserções de Promises e uma breaking change nos arquivos .d.ts que podem ser lidas lá no artigo oficial do lançamento.