Alguns dias atrás, anunciamos a disponibilidade do nosso candidato a lançamento (RC) do TypeScript 3.4. Nossa esperança é coletar comentários e questões iniciais para garantir que nosso lançamento final seja fácil de usar e usar imediatamente.
Para começar a usar o RC, você pode acessá- lo através do NuGet ou usar o npm com o seguinte comando:
npm install -g typescript@rc
Você também pode obter suporte do editor
Vamos explorar o que há de novo no 3.4!
Este artigo em nosso blog.Construções subsequentes mais rápidas com o sinalizador --incremental
Como os arquivos TypeScript são compilados, ele apresenta uma etapa intermediária entre escrever e executar seu código. Um dos nossos objetivos é minimizar o tempo de construção, dada qualquer alteração no seu programa. Uma maneira de fazer isso é executando o TypeScript no modo --watch
. Quando um arquivo é alterado no modo --watch
, o TypeScript pode usar o gráfico de dependência do seu projeto para determinar quais arquivos podem ter sido afetados e precisam ser verificados novamente e reemitidos. Isso pode evitar uma verificação completa do tipo e reemitir, o que pode ser caro.
Mas não é realista esperar que todos os usuários mantenham um processo tsc --watch
execução durante a noite apenas para ter compilações mais rápidas amanhã de manhã. E as construções a frio? Nos últimos meses, trabalhamos para verificar se há uma maneira de salvar as informações apropriadas do modo --watch
em um arquivo e usá-las de compilação para compilação.
O TypeScript 3.4 apresenta um novo sinalizador chamado --incremental
que informa ao TypeScript para salvar informações sobre o gráfico do projeto desde a última compilação. Na próxima vez que o TypeScript for chamado com --incremental
, ele usará essas informações para detectar a maneira mais barata de verificar o tipo e emitir alterações em seu projeto.
Por padrão, com essas configurações, quando executamos o tsc, o TypeScript procurará um arquivo chamado .tsbuildinfo
em nosso diretório de saída ( ./lib
). Se ./lib/.tsbuildinfo
não existir, será gerado. Mas, se o fizer, o tsc
tentará usar esse arquivo para verificar incrementalmente o tipo e atualizar nossos arquivos de saída.
Esses arquivos .tsbuildinfo
podem ser excluídos com segurança e não afetam nosso código em tempo de execução - eles são puramente usados para tornar as compilações mais rápidas. Também podemos nomear o que quisermos e colocá-lo em qualquer lugar que quisermos usando o sinalizador --tsBuildInfoFile
.
Desde que ninguém mais tente gravar no mesmo arquivo de cache, poderemos desfrutar de compilações a frio incrementais mais rápidas.
Projetos compostos
Parte da intenção com projetos compostos ( tsconfig.json
s com composite
definido como true
) é que as referências entre diferentes projetos podem ser construídas de forma incremental. Dessa forma, os projetos compostos sempre produzirão arquivos .tsbuildinfo
.
outFile
Quando outFile
é usado, o nome do arquivo de informações de construção será baseado no nome do arquivo de saída. Por exemplo, se nosso arquivo JavaScript de saída for ./output/foo.js
, sob o sinalizador --incremental
, o TypeScript gerará o arquivo ./output/foo.tsbuildinfo
. Como acima, isso pode ser controlado com o sinalizador --tsBuildInfoFile
.
O formato de arquivo --incremental
e a versão
Embora o arquivo gerado por --incremental
seja JSON, o arquivo não deve ser consumido por nenhuma outra ferramenta. Não podemos fornecer garantias de estabilidade para seu conteúdo e, de fato, nossa política atual é que qualquer versão do TypeScript não entenda os arquivos .tsbuildinfo
gerados a partir de outra versão.
Melhorias para as tuplas ReadonlyArray
e readonly
O TypeScript 3.4 facilita um pouco o uso de tipos de matriz somente leitura.
Uma nova sintaxe para o ReadonlyArray
O tipo ReadonlyArray
descreve as Array
que só podem ser lidas. Qualquer variável com um identificador para um ReadonlyArray
não pode adicionar, remover ou substituir nenhum elemento da matriz.
function foo(arr: ReadonlyArray<string>) { arr.slice();
Embora muitas vezes seja uma boa prática usar o ReadonlyArray
sobre Array
para fins de intenção, muitas vezes tem sido uma dor, uma vez que as matrizes têm uma sintaxe mais agradável. Especificamente, o number[]
é uma versão abreviada da Array<number>
, assim como a Date[]
é uma abreviação da Array<Date>
.
O TypeScript 3.4 introduz uma nova sintaxe para o ReadonlyArray
usando um novo modificador readonly
para tipos de array.
function foo(arr: readonly string[]) { arr.slice();
tuplas readonly
O TypeScript 3.4 também apresenta novo suporte para tuplas readonly
. Podemos prefixar qualquer tipo de tupla com a palavra-chave readonly
para torná-la uma tupla readonly
, assim como podemos agora com a sintaxe abreviada da matriz. Como você pode esperar, diferentemente das tuplas comuns, nas quais os slots podem ser gravados, as tuplas somente leitura permitem a leitura dessas posições.
function foo(pair: readonly [string, string]) { console.log(pair[0]);
Da mesma forma que tuplas comuns são tipos que se estendem da Array
- uma tupla com elementos do tipo T
1
, T
, ... n
se estende da Array<
T
1
| T
2
... T
n
>
- tuplas readonly
são tipos que se estendem do ReadonlyArray
. Portanto, uma tupla readonly
com elementos T
1
, T
2
, ... T
n
se estende de ReadonlyArray<
T
1
| T
2
... T
n
>
.
modificadores de tipo mapeados readonly
readonly
e matrizes readonly
Nas versões anteriores do TypeScript, generalizamos os tipos mapeados para operar de maneira diferente nos tipos de matriz. Isso significava que um tipo mapeado como o Boxify
poderia funcionar em matrizes e tuplas.
interface Box<T> { value: T } type Boxify<T> = { [K in keyof T]: Box<T[K]> }
Infelizmente, tipos mapeados como o tipo de utilitário Readonly
eram efetivamente não ops nos tipos de matriz e tupla.
No TypeScript 3.4, o modificador readonly
em um tipo mapeado converte automaticamente tipos semelhantes a matrizes em seus correspondentes readonly
correspondentes.
Da mesma forma, você pode escrever um tipo de utilitário como o tipo mapeado Writable
que retira o readonly
-ness e converte os contêineres do array readonly
volta aos seus equivalentes mutáveis.
type Writable<T> = { -readonly [K in keyof T]: T[K] }
Advertências
Apesar de sua aparência, o modificador de tipo readonly
pode ser usado para sintaxe em tipos de matriz e tupla. Não é um operador do tipo de uso geral.
let err1: readonly Set<number>;
afirmações const
Ao declarar uma variável ou propriedade mutável, o TypeScript geralmente amplia os valores para garantir que possamos atribuir coisas posteriormente, sem escrever um tipo explícito.
let x = "hello";
Tecnicamente, todo valor literal tem um tipo literal. Acima, o tipo "hello"
foi ampliado para a string
tipos antes de inferir um tipo para x
.
Uma visão alternativa pode ser dizer que x
tem o tipo literal original "hello"
e que não podemos atribuir "world"
posteriormente assim:
let x: "hello" = "hello";
Nesse caso, isso parece extremo, mas pode ser útil em outras situações. Por exemplo, os TypeScripters geralmente criam objetos que devem ser usados em uniões discriminadas.
type Shape = | { kind: "circle", radius: number } | { kind: "square", sideLength: number } function getShapes(): readonly Shape[] { let result = [ { kind: "circle", radius: 100, }, { kind: "square", sideLength: 50, }, ];
A mutabilidade é uma das melhores heurísticas de intenção que o TypeScript pode usar para determinar quando ampliar (em vez de analisar todo o programa).
Infelizmente, como vimos no último exemplo, no JavaScript, as propriedades são mutáveis por padrão. Isso significa que o idioma geralmente alarga tipos indesejáveis, exigindo tipos explícitos em determinados lugares.
function getShapes(): readonly Shape[] {
Até certo ponto, tudo bem, mas, conforme nossas estruturas de dados se tornam cada vez mais complexas, isso se torna complicado.
Para resolver isso, o TypeScript 3.4 apresenta uma nova construção para valores literais chamados const
assertions. Sua sintaxe é uma asserção de tipo com const
no lugar do nome do tipo (por exemplo, 123 as const
). Quando construímos novas expressões literais com afirmações const
, podemos sinalizar para a linguagem que
- nenhum tipo literal nessa expressão deve ser ampliado (por exemplo, não é possível passar de
"hello"
para string
) - literais de objeto obtêm propriedades
readonly
- literais de matriz tornam-se tuplas
readonly
Fora dos arquivos .tsx
, a sintaxe da asserção de colchetes angulares também pode ser usada.
Esse recurso geralmente significa que tipos que de outra forma seriam usados apenas para sugerir imutabilidade ao compilador podem ser omitidos.
Observe que as anotações acima não eram necessárias. A afirmação const
permitiu que o TypeScript usasse o tipo mais específico da expressão.
Advertências
Uma coisa a notar é que as asserções const
só podem ser aplicadas imediatamente em expressões literais simples.
Outra coisa a ter em mente é que os contextos const
não convertem imediatamente uma expressão para ser totalmente imutável.
let arr = [1, 2, 3, 4]; let foo = { name: "foo", contents: arr, }; foo.name = "bar";
Verificação de globalThis
para globalThis
Pode ser surpreendentemente difícil acessar ou declarar valores no escopo global, talvez porque estamos escrevendo nosso código em módulos (cujas declarações locais não vazam por padrão) ou porque podemos ter uma variável local que oculta o nome de um valor global. Em ambientes diferentes, existem maneiras diferentes de acessar qual é efetivamente o escopo global - global
em Nó, window
, self
ou frames
no navegador ou em determinados locais fora do modo estrito. Nada disso é óbvio, e geralmente deixa os usuários inseguros se estão escrevendo o código correto.
O TypeScript 3.4 apresenta suporte para a verificação global do novo globalThis
do ECMAScript - uma variável global que, bem, se refere ao escopo global. Diferente das soluções acima, globalThis
fornece uma maneira padrão de acessar o escopo global que pode ser usado em diferentes ambientes.
globalThis
também é capaz de refletir se uma variável global foi ou não declarada como uma const
, tratando-a como uma propriedade readonly
quando acessada.
const answer = 42; globalThis.answer = 333333;
É importante observar que o TypeScript não transforma referências ao globalThis
ao compilar para versões mais antigas do ECMAScript. Dessa forma, a menos que você esteja direcionando navegadores sempre verdes (que já oferecem suporte a globalThis
), convém usar um polyfill apropriado .
Converter em parâmetros nomeados
Às vezes, as listas de parâmetros começam a ficar pesadas.
function updateOptions( hue?: number, saturation?: number, brightness?: number, positionX?: number, positionY?: number positionZ?: number) {
No exemplo acima, é muito fácil para um chamador misturar a ordem dos argumentos fornecidos. Um padrão JavaScript comum é usar um "objeto de opções", para que cada opção seja explicitamente nomeada e a ordem nunca importe. Isso emula um recurso que outros idiomas chamaram de "parâmetros nomeados".
interface Options { hue?: number, saturation?: number, brightness?: number, positionX?: number, positionY?: number positionZ?: number } function updateOptions(options: Options = {}) {
A equipe do TypeScript não trabalha apenas em um compilador - também fornecemos a funcionalidade que os editores usam para recursos avançados, como conclusões, definição e refatoração. No TypeScript 3.4, nossa estagiária Gabriela Britto implementou uma nova refatoração para converter funções existentes para usar esse padrão de "parâmetros nomeados".

Embora possamos alterar o nome do recurso em nosso lançamento final 3.4 e acreditamos que possa haver espaço para algumas das ergonomia, gostaríamos que você experimentasse o recurso e nos desse seu feedback.
Quebrando mudanças
Agora, o nível superior está digitado
O tipo de nível superior agora é digitado como typeof globalThis
vez de any
. Como conseqüência, você pode receber erros por acessar valores desconhecidos sobre this
em noImplicitAny
.
Observe que o código compilado no noImplicitThis
não apresentará nenhuma alteração aqui.
Argumentos de tipo genérico propagado
Em certos casos, a inferência aprimorada do TypeScript 3.4 pode produzir funções que são genéricas, em vez daquelas que recebem e retornam suas restrições (geralmente {}
).
declare function compose<T, U, V>(f: (arg: T) => U, g: (arg: U) => V): (arg: T) => V; function list<T>(x: T) { return [x]; } function box<T>(value: T) { return { value }; } let f = compose(list, box); let x = f(100)
Uma anotação de tipo explícita em x
pode se livrar do erro.
O que vem a seguir?
O TypeScript 3.4 é a nossa primeira versão que teve um plano de iteração descrevendo nossos planos para esta versão, que deve se alinhar ao nosso roteiro de 6 meses . Você pode ficar de olho em ambos e em nossa página do roteiro dos recursos contínuos para qualquer trabalho futuro.
No momento, estamos ansiosos para ouvir sobre sua experiência com o RC, então experimente agora e deixe-nos saber seus pensamentos!