Você está na página 1de 139

15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com

fdc3 com TypeScri…

Página 1

Esta cópia do manual do TypeScript foi


criado na segunda-feira, 15 de novembro de 2021 contra
comprometer-se f2fdc3 comTypeScript 4.4.

Página 2

Índice

https://translate.googleusercontent.com/translate_f 1/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
O Manual do TypeScript Sua primeira etapa para aprender TypeScript
O básico Etapa um no aprendizado do TypeScript: os tipos básicos.
Tipos do dia a dia Os primitivos de linguagem.
Entenda como o TypeScript usa conhecimento de JavaScript
Estreitando
para reduzir a quantidade de sintaxe de tipo em seus projetos.
Mais sobre funções Aprenda como as funções funcionam no TypeScript.
Como o TypeScript descreve as formas do JavaScript
Tipos de Objetos
objetos.
Uma visão geral das maneiras pelas quais você pode criar mais
Criação de tipos a partir de tipos
tipos de tipos existentes.
Genéricos Tipos que levam parâmetros
Operador do tipo chave Usando o operador keyof em contextos de tipo.
Operador de tipo Usando o operador typeof em contextos de tipo.
Tipos de acesso indexados Usando a sintaxe Type ['a'] para acessar um subconjunto de um tipo.
Crie tipos que agem como instruções if no tipo
Tipos condicionais
sistema.
Tipos mapeados Gerando tipos reutilizando um tipo existente.
Gerar tipos de mapeamento que alteram propriedades por meio de
Tipos literais de modelo
strings literais de modelo.
Aulas Como as classes funcionam no TypeScript
Como o JavaScript lida com a comunicação entre arquivos
Módulos
limites.

Página 3

O Manual do TypeScript

Sobre este manual


Mais de 20 anos após sua introdução à comunidade de programação, JavaScript é agora um dos
as linguagens de plataforma cruzada mais difundidas já criadas. Começando como uma pequena linguagem de script para
adicionando interatividade trivial às páginas da web, o JavaScript cresceu e se tornou uma linguagem de escolha para ambos
aplicativos de front-end e back-end de todos os tamanhos. Embora o tamanho, escopo e complexidade dos programas
escrito em JavaScript cresceu exponencialmente, a capacidade da linguagem JavaScript de expressar o
relações entre diferentes unidades de código, não. Combinado com o bastante peculiar do JavaScript
semântica de tempo de execução, essa incompatibilidade entre a linguagem e a complexidade do programa tornou o JavaScript
desenvolvimento uma tarefa difícil de gerenciar em escala.

Os tipos de erros mais comuns que os programadores escrevem podem ser descritos como erros de tipo: a
certo tipo de valor foi usado quando um tipo diferente de valor era esperado. Isso pode ser devido a
erros de digitação simples, uma falha em entender a superfície da API de uma biblioteca, suposições incorretas sobre
comportamento em tempo de execução ou outros erros. O objetivo do TypeScript é ser um verificador de tipos estático para JavaScript

https://translate.googleusercontent.com/translate_f 2/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
programas - em outras palavras, uma ferramenta que é executada antes que seu código seja executado (estático) e garante que os tipos
do programa estão corretos (tipo verificado).

Se você está chegando ao TypeScript sem um fundo de JavaScript, com a intenção de TypeScript
sendo seu primeiro idioma, recomendamos que você primeiro comece a ler a documentação sobre o
Tutorial do Microsoft Aprenda JavaScript ou leiaJavaScript no Mozilla Web Docs . Se você tem
experiência em outras linguagens, você deve ser capaz de aprender a sintaxe JavaScript rapidamente
lendo o manual.

Como este manual está estruturado


O manual está dividido em duas seções:

O Manual

O Manual do TypeScript se destina a ser um documento abrangente que explica o TypeScript


para programadores comuns. Você pode ler o manual indo de cima para baixo no lado esquerdo
navegação manual.

Você deve esperar que cada capítulo ou página forneça um forte entendimento do dado
conceitos. O Manual do TypeScript não é uma especificação de linguagem completa, mas destina-se a
seja um guia completo de todos os recursos e comportamentos da linguagem.

Um leitor que conclui o passo a passo deve ser capaz de:

Página 4
Leia e entenda a sintaxe e os padrões do TypeScript comumente usados

Explique os efeitos de opções importantes do compilador

Prever corretamente o comportamento do sistema de tipo na maioria dos casos

No interesse da clareza e da brevidade, o conteúdo principal do Manual não explorará todos


caso extremo ou minúcias dos recursos que estão sendo cobertos. Você pode encontrar mais detalhes em particular
conceitos nos artigos de referência.

Arquivos de Referência

A seção de referência abaixo do manual na navegação foi construída para fornecer uma
compreensão de como uma parte específica do TypeScript funciona. Você pode ler de cima para baixo, mas
cada seção tem como objetivo fornecer uma explicação mais profunda de um único conceito - o que significa que não há objetivo
para continuidade.

Não Objetivos

O Manual também pretende ser um documento conciso que pode ser lido confortavelmente em alguns
horas. Certos tópicos não serão cobertos para manter as coisas curtas.

Especificamente, o manual não apresenta totalmente os fundamentos básicos do JavaScript, como funções, classes e
fechamentos. Quando apropriado, incluiremos links para leituras de histórico que você pode usar para ler
nesses conceitos.

O manual também não pretende ser um substituto para uma especificação de idioma. Em alguns casos,
casos extremos ou descrições formais de comportamento serão ignorados em favor de soluções de alto nível e mais fáceis de
entender as explicações. Em vez disso, existem páginas de referência separadas que mais precisamente e
descreve formalmente muitos aspectos do comportamento do TypeScript. As páginas de referência não se destinam a
leitores não familiarizados com o TypeScript, então eles podem usar terminologia avançada ou tópicos de referência que você
não li sobre ainda.

Finalmente, o manual não cobrirá como o TypeScript interage com outras ferramentas, exceto onde
necessário. Tópicos como como configurar o TypeScript com webpack, rollup, parcel, react, babel, closure,
lerna, rush, bazel, preact, vue, angular, svelte, jquery, yarn ou npm estão fora do escopo - você pode encontrar
esses recursos em outros lugares da web.

https://translate.googleusercontent.com/translate_f 3/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Iniciar
Antes de começar com o básico , recomendamos a leitura de um dos seguintes itens introdutórios
Páginas. Estas introduções têm como objetivo destacar as principais semelhanças e diferenças entre
TypeScript e sua linguagem de programação preferida, e esclarecer equívocos comuns
específicos para esses idiomas.

Página 5
TypeScript para novos programadores

TypeScript para programadores JavaScript

TypeScript para programadores OOP

TypeScript para programadores funcionais

Caso contrário, pule para The Basics ou pegue uma cópia no Epub ouFormulário PDF .

Página 6

https://translate.googleusercontent.com/translate_f 4/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

O básico
Cada valor em JavaScript tem um conjunto de comportamentos que você pode observar executando diferentes
operações. Isso parece abstrato, mas como um exemplo rápido, considere algumas operações que podemos executar
em uma variável chamada mensagem .

// Acessando a propriedade 'toLowerCase'


// na 'mensagem' e, em seguida, chamando-a
mensagem . toLowerCase ();

// Chamando 'mensagem'
mensagem ();

Se dividirmos isso, a primeira linha executável de código acessa uma propriedade chamada toLowerCase e
então chama. O segundo tenta chamar a mensagem diretamente.

Mas, supondo que não saibamos o valor da mensagem - e isso é bastante comum - não podemos
diga quais resultados obteremos ao tentar executar qualquer um desses códigos. O comportamento de cada operação
depende inteiramente do valor que tínhamos em primeiro lugar.

A mensagem pode ser chamada?

Ele tem uma propriedade chamada toLowerCase nele?

Em caso afirmativo, toLowerCase pode ser chamado ?

Se ambos os valores puderem ser chamados, o que eles retornarão?

As respostas a essas perguntas geralmente são coisas que mantemos em nossas cabeças quando escrevemos JavaScript,
e esperamos ter acertado em todos os detalhes.

Digamos que a mensagem foi definida da seguinte maneira.

const message = "Olá, mundo!" ;

Como você provavelmente pode imaginar, se tentarmos executar message.toLowerCase () , obteremos a mesma string
apenas em minúsculas.

Página 7
E quanto à segunda linha de código? Se você estiver familiarizado com JavaScript, saberá que isso falha com um
exceção:

TypeError: a mensagem não é uma função

Seria ótimo se pudéssemos evitar erros como esse.

Quando executamos nosso código, a maneira que nosso tempo de execução JavaScript escolhe o que fazer é descobrir
o tipo de valor - que tipos de comportamentos e capacidades ele possui. Isso é parte do que
TypeError está aludindo a - está dizendo que a string "Hello World!" não pode ser chamado de
função.

Para alguns valores, como string e número primitivos , podemos identificar seu tipo em tempo de execução
usando o operador typeof . Mas para outras coisas como funções, não há tempo de execução correspondente
https://translate.googleusercontent.com/translate_f 5/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

mecanismo para identificar seus tipos. Por exemplo, considere esta função:

função fn ( x ) {
return x . flip ();
}

Podemos observar lendo o código que esta função só funcionará se for fornecido um objeto com um
propriedade flip que pode ser chamada , mas o JavaScript não mostra essas informações de uma maneira que possamos verificar
enquanto o código está sendo executado. A única maneira em JavaScript puro de dizer o que fn faz com um determinado
valor é chamá-lo e ver o que acontece. Esse tipo de comportamento torna difícil prever qual código
fará antes de ser executado, o que significa que é mais difícil saber o que seu código fará enquanto você
escrevendo.

Visto desta forma, um tipo é o conceito de descrever quais valores podem ser passados ​para fn e quais
irá falhar. JavaScript fornece apenas digitação dinâmica - executando o código para ver o que acontece.

A alternativa é usar um sistema de tipo estático para fazer previsões sobre qual código é esperado
antes de ser executado.

Verificação de tipo estática


Pense no TypeError que obtivemos antes ao tentar chamar uma string como uma função. Maioria
as pessoas não gostam de receber nenhum tipo de erro ao executar seu código - esses são considerados bugs!
E quando escrevemos um novo código, tentamos nosso melhor para evitar a introdução de novos bugs.

Página 8
Se adicionarmos apenas um pouco de código, salvar nosso arquivo, executar novamente o código e ver imediatamente o erro, poderemos
ser capaz de isolar o problema rapidamente; mas nem sempre é o caso. Podemos não ter testado o
recurso completamente o suficiente, para que nunca possamos realmente encontrar um erro potencial que seria
jogado! Ou se tivéssemos a sorte de testemunhar o erro, poderíamos acabar fazendo grandes
refatorações e adição de muitos códigos diferentes que somos forçados a vasculhar.

Idealmente, poderíamos ter uma ferramenta que nos ajudasse a encontrar esses bugs antes que nosso código fosse executado. Isso é o que é um estático
verificador de tipo como o TypeScript faz. Os sistemas de tipos estáticos descrevem as formas e comportamentos de quais
nossos valores estarão quando executarmos nossos programas. Um verificador de tipo como o TypeScript usa essa informação
e nos diz quando as coisas podem estar saindo dos trilhos.

const mensagem = "olá!" ;

mensagem ();

Esta
Esta expressão
expressão não
não pode
pode ser
ser chamada.
chamada.
O
O tipo
tipo 'String'
'String' não
não tem
tem assinaturas
assinaturas de
de chamada.
chamada.

Executar essa última amostra com TypeScript nos dará uma mensagem de erro antes de executarmos o código em
o primeiro lugar.

Falhas de não exceção


Até agora, discutimos certas coisas como erros de tempo de execução - casos em que o tempo de execução de JavaScript
diz-nos que pensa que algo é absurdo. Esses casos surgem porque o ECMAScript
especificação tem instruções explícitas sobre como a linguagem deve se comportar quando se depara com
algo inesperado.

https://translate.googleusercontent.com/translate_f 6/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Por exemplo, a especificação diz que tentar chamar algo que não pode ser chamado deve lançar um
erro. Talvez isso soe como "comportamento óbvio", mas você pode imaginar que acessar uma propriedade
que não existe em um objeto deve gerar um erro também. Em vez disso, o JavaScript nos dá diferentes
comportamento e retorna o valor indefinido :

const user = {
nome: "Daniel" ,
idade: 26 ,
};

usuário . localização ; // retorna indefinido

Página 9
Em última análise, um sistema de tipo estático deve fazer a chamada sobre qual código deve ser sinalizado como um erro em
seu sistema, mesmo se for um JavaScript "válido" que não gerará um erro imediatamente. No TypeScript, o
o código a seguir produz um erro sobre o local não ser definido:

const user = {
nome: "Daniel" ,
idade: 26 ,
};

usuário . localização ;

A
A propriedade
propriedade 'local'
'local' não
não existe
existe no
no tipo
tipo '{nome:
'{nome: string;
string; era:
idade: número;
número;
} '. } '.

Embora às vezes isso implique uma troca no que você pode expressar, a intenção é capturar
bugs em nossos programas. E o TypeScript detecta muitos bugs legítimos.

Por exemplo: erros de digitação,

anúncio const = "Olá, mundo!" ;

// Com que rapidez você consegue identificar os erros de digitação?


anúncio . toLocaleLowercase ();
anúncio . toLocalLowerCase ();

// Provavelmente pretendíamos escrever isso ...


anúncio . toLocaleLowerCase ();

funções desnecessárias,

function flipCoin () {
// Pretende ser Math.random ()
return Math . aleatório < 0,5 ;

O
O operador
operador '<'
'<' não
não pode
pode ser
ser aplicado
aplicado aos
aos tipos
tipos '()
'() =>
=> número'
número' ee 'número'.
'número'.

ou erros básicos de lógica.

https://translate.googleusercontent.com/translate_f 7/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 10

valor const = matemática . aleatório () < 0,5 ? "a" : "b" ;


if ( valor ! == "a" ) {
// ...
} else if ( value === "b" ) {

Esta
Esta condição
condição sempre
sempre retornará
retornará 'falso'
'falso' uma
uma vez
vez que
que os
os tipos
tipos '"a"'
'"a"' ee '"b"'
'"b"'
não tem
não sobreposição.
tem sobreposição.

// Ops, inacessível
}

Tipos de ferramentas
O TypeScript pode detectar bugs quando cometemos erros em nosso código. Isso é ótimo, mas o TypeScript pode
também nos impede de cometer esses erros em primeiro lugar.

O verificador de tipo tem informações para verificar coisas como se estamos acessando as propriedades certas
em variáveis ​e outras propriedades. Assim que tiver essas informações, ele também pode começar a sugerir quais
propriedades que você pode querer usar.

Isso significa que o TypeScript pode ser aproveitado para editar código também, e o verificador de tipo principal pode
fornecer mensagens de erro e autocompletar código conforme você digita no editor. Isso faz parte do que as pessoas
costumam se referir quando falam sobre ferramentas no TypeScript.

importar expresso de "expresso" ;


const app = express ();

app . get ( "/" , função ( req , res ) {


res . sen
sen d
});
sen dDate

sen dfile
app . ouvir ( 3000 );
sen dFile

O TypeScript leva as ferramentas a sério e isso vai além de conclusões e erros à medida que você digita. Um
editor que suporta TypeScript pode fornecer "soluções rápidas" para corrigir erros automaticamente, refatorações para
facilmente reorganizar o código e recursos de navegação úteis para pular para as definições de uma variável, ou
encontrar todas as referências a uma determinada variável. Tudo isso é construído em cima do verificador de tipo e é totalmente
multiplataforma, então é provável que seu editor favorito tem suporte para TypeScript disponível .

Página 11

tsc , o compilador typescript


Falamos sobre verificação de tipo, mas ainda não usamos nosso verificador de tipo. Vamos pegar
familiarizado com o nosso novo amigo tsc , o compilador original datilografado. Primeiro, precisamos pegá-lo via npm.

npm install -g typescript

https://translate.googleusercontent.com/translate_f 8/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Isso instala o texto datilografado Compiler tsc globalmente. Você pode usar npx ou ferramentas semelhantes se preferir
em vez disso, execute tsc a partir de um pacote node_modules local .

Agora vamos para uma pasta vazia e tente escrever nosso primeiro programa TypeScript : hello.ts :

// Cumprimenta o mundo.
console . log ( "Olá, mundo!" );

Observe que não há frescuras aqui; este programa "hello world" parece idêntico ao que você escreveria para um
Programa "hello world" em JavaScript. E agora vamos verificar o tipo executando o comando tsc
que foi instalado para nós pelo pacote typescript .

tsc hello.ts

Tada!

Espere, "tada" o que exatamente? Corremos tsc e nada aconteceu! Bem, não houve erros de tipo, então
não obtivemos nenhuma saída em nosso console, pois não havia nada a relatar.

Mas verifique novamente - em vez disso, obtivemos alguma saída de arquivo. Se olharmos em nosso diretório atual, veremos um
arquivo hello.js próximo a hello.ts . Essa é a saída do nosso hello.ts arquivo após tsc compila
ou o transforma em um arquivo JavaScript simples. E se verificarmos o conteúdo, veremos o que TypeScript
cospe depois de processar um arquivo .ts :

// Cumprimenta o mundo.
console . log ( "Olá, mundo!" );

Página 12
Nesse caso, havia muito pouco para o TypeScript transformar, então parece idêntico ao que escrevemos.
O compilador tenta emitir um código legível limpo que se parece com algo que uma pessoa escreveria.
Embora nem sempre seja tão fácil, o TypeScript recua de forma consistente, e fica atento a quando nosso código se estende
em diferentes linhas de código e tenta manter os comentários por perto.

E se introduzíssemos um erro de verificação de tipo? Vamos reescrever hello.ts :

// Esta é uma função de saudação de uso geral de nível industrial:


função saudação ( pessoa , data ) {
console . log ( `Olá $ { person } , hoje é $ { date } !` );
}

cumprimentar ( "Brendan" );

Se executarmos tsc hello.ts novamente, observe que obteremos um erro na linha de comando!

Esperava-se 2 argumentos, mas obteve 1.

O TypeScript está nos dizendo que esquecemos de passar um argumento para a função greet , e com razão. Então
agora nós apenas escrevemos JavaScript padrão, e ainda a verificação de tipo ainda foi capaz de encontrar problemas
com nosso código. Obrigado TypeScript!

https://translate.googleusercontent.com/translate_f 9/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Emitindo com erros


Uma coisa que você pode não ter notado no último exemplo foi que nosso arquivo hello.js mudou
novamente. Se abrirmos esse arquivo, veremos que o conteúdo ainda é basicamente o mesmo que o nosso
Arquivo de entrada. Isso pode ser um pouco surpreendente, dado o fato de que tsc relatou um erro sobre nosso código,
mas isso é baseado em um dos valores fundamentais do TypeScript: na maior parte do tempo, você saberá melhor do que
TypeScript.

Para reiterar o que foi dito anteriormente, o código de verificação de tipo limita os tipos de programas que você pode executar e, portanto, há
uma compensação sobre os tipos de coisas que um verificador de tipo considera aceitáveis. Na maioria das vezes está tudo bem, mas
existem cenários em que essas verificações atrapalham. Por exemplo, imagine-se migrando
Código JavaScript para TypeScript e introdução de erros de verificação de tipo. Eventualmente você obterá
em torno de limpar as coisas para o verificador de tipo, mas o código JavaScript original já estava
trabalhando! Por que convertê-lo em TypeScript deve impedir você de executá-lo?

Portanto, o TypeScript não atrapalha. Claro, com o tempo, você pode querer ser um pouco mais
defensiva contra erros e faça com que o TypeScript aja um pouco mais estritamente. Nesse caso, você pode usar o

Página 13
Opção do compilador noEmitOnError . Tente alterar seu arquivo hello.ts e executar tsc com ele
bandeira:

tsc --noEmitOnError hello.ts

Você notará que hello.js nunca é atualizado.

Tipos explícitos
Até agora, não dissemos ao TypeScript o que é pessoa ou data . Vamos editar o código para contar
TypeScript aquela pessoa é uma string e essa data deve ser um objeto Date . Também usaremos o

método toDateString () na data .

função saudação ( pessoa : string , data : Data ) {


console . log ( `Olá $ { person } , hoje é $ { date . toDateString () } !` );
}

O que fizemos foi adicionar anotações de tipo em pessoa e data para descrever quais tipos de valores

saudar pode ser chamado com. Você pode ler essa assinatura como " saudar leva uma pessoa do tipo
string e uma data do tipo Date ".

Com isso, o TypeScript pode nos informar sobre outros casos em que saudação pode ter sido chamada incorretamente.
Por exemplo...

função saudação ( pessoa : string , data : Data ) {


console . log ( `Olá $ { person } , hoje é $ { date . toDateString () } !` );
}

cumprimentar ( "Maddison" , Data ());

O
O argumento
argumento do
do tipo
tipo 'string'
'string' não
não épode
atribuível
ser atribuído
ao parâmetro
ao parâmetro
do tipo do tipo 'Data'.
'Encontro'.

https://translate.googleusercontent.com/translate_f 10/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Huh? O TypeScript relatou um erro em nosso segundo argumento, mas por quê?

Página 14
Talvez surpreendentemente, chamar Date () em JavaScript retorna uma string . Por outro lado,
construir um Date com new Date () realmente nos dá o que estávamos esperando.

De qualquer forma, podemos corrigir o erro rapidamente:

função saudação ( pessoa : string , data : Data ) {


console . log ( `Olá $ { person } , hoje é $ { date . toDateString () } !` );
}

saudar ( "Maddison" , nova data ());

Lembre-se de que nem sempre precisamos escrever anotações de tipo explícitas. Em muitos casos, o TypeScript pode
até mesmo apenas inferir (ou "descobrir") os tipos para nós, mesmo que os omitamos.

deixe msg = "olá!" ;

deixe msg: string

Embora não tenhamos informado ao TypeScript que msg tinha a string de tipo, ela foi capaz de descobrir isso.
Esse é um recurso e é melhor não adicionar anotações quando o sistema de tipo acabar inferindo
o mesmo tipo de qualquer maneira.

Observação: o balão de mensagem dentro do exemplo de código acima. Isso é o que seu editor mostraria se você tivesse

pairou sobre a palavra.

Tipos apagados
Vamos dar uma olhada no que acontece quando compilamos a função acima greet com tsc para a saída
JavaScript:

"use estrito" ;
função saudação ( pessoa , data ) {
console . log ( "Olá" + pessoa + ", hoje é" + data . toDateString () +
}
saudar ( "Maddison" , nova data ());

Página 15
Observe duas coisas aqui:

1. Nossos parâmetros de pessoa e data não têm mais anotações de tipo.


2. Nossa "string de modelo" - aquela string que usava crases (o caractere ` ) - foi convertida para
strings simples com concatenações ( + ).

https://translate.googleusercontent.com/translate_f 11/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Mais sobre esse segundo ponto mais tarde, mas vamos agora nos concentrar nesse primeiro ponto. As anotações de tipo não fazem parte
de JavaScript (ou ECMAScript para ser pedante), então realmente não existem navegadores ou outros tempos de execução
que pode apenas executar o TypeScript sem modificações. É por isso que o TypeScript precisa de um compilador em primeiro lugar -
ele precisa de alguma forma de eliminar ou transformar qualquer código específico do TypeScript para que você possa executá-lo.
A maior parte do código específico do TypeScript é apagado e, da mesma forma, aqui nossas anotações de tipo foram
completamente apagado.

Lembre - se : as anotações de tipo nunca alteram o comportamento do tempo de execução do seu programa.

Downleveling
Uma outra diferença em relação ao anterior é que nossa string de modelo foi reescrita a partir de

`Olá $ { person } , hoje é $ { date . toDateString () } ! ` ;

para

"Olá" + pessoa + ", hoje é" + data . toDateString () + "!" ;

Por quê isso aconteceu?

Strings de modelo são um recurso de uma versão do ECMAScript chamado ECMAScript 2015 (também conhecido como
ECMAScript 6, ES2015, ES6, etc. - não pergunte). TypeScript tem a capacidade de reescrever o código do mais recente
versões de ECMAScript para versões mais antigas, como ECMAScript 3 ou ECMAScript 5 (também conhecido como ES3 e ES5).
Este processo de mudança de uma versão mais nova ou "superior" do ECMAScript para uma versão mais antiga ou
o "mais baixo" às vezes é chamado de downleveling.

Por padrão, o TypeScript tem como alvo o ES3, uma versão extremamente antiga do ECMAScript. Poderíamos ter escolhido
algo um pouco mais recente usando o opção de destino . Executando com --target es2015
altera o TypeScript para o ECMAScript 2015, o que significa que o código deve ser executado em qualquer lugar
ECMAScript 2015 é compatível. Então, executando tsc --target es2015 hello.ts nos dá o
seguinte saída:

Página 16

função saudação ( pessoa , data ) {


console . log ( `Olá $ { person } , hoje é $ { date . toDateString () } !` );
}
saudar ( "Maddison" , nova data ());

Embora o destino padrão seja ES3, a grande maioria dos navegadores atuais suporta ES2015. A maioria dos desenvolvedores

pode, portanto, especificar com segurança ES2015 ou superior como um alvo, a menos que seja compatível com certos
navegadores é importante.

Rigor
Diferentes usuários vêm para o TypeScript procurando por coisas diferentes em um verificador de tipos. Algumas pessoas são
procurando uma experiência de aceitação mais flexível, que pode ajudar a validar apenas algumas partes de seus
programa, e ainda tem ferramentas decentes. Esta é a experiência padrão com TypeScript, onde os tipos
são opcionais, a inferência leva os tipos mais tolerantes e não há verificação de
valores nulos / indefinidos . Muito parecido com como tsc emite em face de erros, esses padrões são colocados em

https://translate.googleusercontent.com/translate_f 12/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
lugar para ficar fora do seu caminho. Se você estiver migrando o JavaScript existente, pode ser desejável primeiro
Passo.

Em contraste, muitos usuários preferem que o TypeScript valide o máximo que puder imediatamente, e
é por isso que o idioma também fornece configurações de rigidez. Essas configurações de rigidez ficam estáticas
verificação de tipo de um switch (seu código é verificado ou não) em algo mais próximo de um dial. o
quanto mais você aumentar esse dial, mais o TypeScript verificará para você. Isso pode exigir um pouco mais
funciona, mas, de um modo geral, se paga a longo prazo e permite verificações mais completas
e ferramentas mais precisas. Quando possível, uma nova base de código deve sempre transformar essa rigidez
verifica.

O TypeScript tem vários sinalizadores de rigidez de verificação de tipo que podem ser ativados ou desativados, e todos os nossos
os exemplos serão escritos com todos eles habilitados, a menos que indicado de outra forma. A bandeira estrita no
CLI, ou "estrito": verdadeiro em umtsconfig.json ativa todos eles simultaneamente, mas podemos
desative-os individualmente. Os dois maiores que você deve conhecer sãonoImplicitAny
e strictNullChecks.

noImplicitAny
Lembre-se de que, em alguns lugares, o TypeScript não tenta inferir tipos para nós e, em vez disso, volta ao
tipo mais tolerante: qualquer . Esta não é a pior coisa que pode acontecer - afinal, recuar para qualquer um é
apenas a experiência simples de JavaScript de qualquer maneira.

Página 17
No entanto, o uso de qualquer frequentemente anula o propósito de usar o TypeScript em primeiro lugar. O mais
digitado em seu programa, mais validação e ferramentas você obterá, o que significa que encontrará menos
bugs enquanto você codifica. Ligando oA sinalização noImplicitAny emitirá um erro em quaisquer variáveis ​cujo
tipo é inferido implicitamente como qualquer .

strictNullChecks
Por padrão, valores como null e undefined podem ser atribuídos a qualquer outro tipo. Isso pode fazer
escrever algum código mais fácil, mas esquecer de lidar com nulos e indefinidos é a causa de inúmeras
insetos do mundo - alguns consideram isso um erro de bilhões de dólares ! osinalizador strictNullChecks torna
lidar com nulos e indefinidos mais explícitos e nos poupa de nos preocupar se
esqueci de lidar com nulo e indefinido .

https://translate.googleusercontent.com/translate_f 13/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 18

Tipos do dia a dia

Neste capítulo, vamos cobrir alguns dos tipos mais comuns de valores que você encontrará no código JavaScript,
e explicar as maneiras correspondentes de descrever esses tipos no TypeScript. Este não é um exaustivo
lista, e os próximos capítulos descreverão mais maneiras de nomear e usar outros tipos.

Os tipos também podem aparecer em muitos mais lugares do que apenas anotações de tipo. Conforme aprendemos sobre os tipos
próprios, também aprenderemos sobre os lugares onde podemos nos referir a esses tipos para formar novos
constrói.

Começaremos revisando os tipos mais básicos e comuns que você pode encontrar ao escrever
Código JavaScript ou TypeScript. Posteriormente, eles formarão os blocos de construção principais de tipos mais complexos.

Os primitivos: string , número e booleano


JavaScript tem três muito comumente usados primitivos: string , número e booleano . Cada um tem um
tipo correspondente no TypeScript. Como você pode esperar, esses são os mesmos nomes que você veria se
usou o operador typeof do JavaScript em um valor desses tipos:

string representa valores de string como "Olá, mundo"

number é para números como 42 . JavaScript não tem um valor de tempo de execução especial para inteiros,
então não há equivalente a int ou float - tudo é simplesmente um número

booleano é para os dois valores verdadeiro e falso

Os nomes de tipo String , Number e Boolean (começando com letras maiúsculas) são válidos, mas referem-se a

alguns tipos internos especiais que muito raramente aparecerão em seu código. Sempre use string , número ou

booleano para tipos.

Matrizes
Para especificar o tipo de uma matriz como [1, 2, 3] , você pode usar a sintaxe número [] ; esta sintaxe
funciona para qualquer tipo (por exemplo, string [] é um array de strings e assim por diante). Você também pode ver isso escrito
como Array <número> , o que significa a mesma coisa. Aprenderemos mais sobre a sintaxe T <U> quando
cobrimos genéricos.

Observe que [número] é uma coisa diferente; consulte a seção sobre Tuplas .

Página 19

https://translate.googleusercontent.com/translate_f 14/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

algum
O TypeScript também tem um tipo especial, any , que você pode usar sempre que não quiser um determinado
valor para causar erros de verificação de tipo.

Quando um valor é do tipo qualquer , você pode acessar quaisquer propriedades dele (que por sua vez serão do tipo

qualquer ), chame-o como uma função, atribua-o a (ou de) um valor de qualquer tipo ou praticamente qualquer outra coisa
isso é sintaticamente legal:

let obj : any = { x: 0 };


// Nenhuma das linhas de código a seguir lançará erros do compilador.
// Usar `any` desativa todas as verificações de tipo posteriores, e é assumido
// você conhece o ambiente melhor do que o TypeScript.
obj . foo ();
obj ();
obj . bar = 100 ;
obj = "olá" ;
const n : número = obj ;

A qualquer tipo é útil quando você não quer escrever uma longa tipo apenas para convencer typescript
que uma determinada linha de código está correta.

noImplicitAny

Quando você não especifica um tipo e o TypeScript não pode inferi-lo do contexto, o compilador normalmente
padrão para qualquer .

No entanto, você geralmente deseja evitar isso, porque nenhum deles não tem verificação de tipo. Use o sinalizador do compilador
noImplicitAny para sinalizar qualquer implícita qualquer como um erro.

Anotações de tipo em variáveis


Ao declarar uma variável usando const , var ou let , você pode opcionalmente adicionar uma anotação de tipo
para especificar explicitamente o tipo da variável:

deixe meuNome : string = "Alice" ;

Página 20
O TypeScript não usa declarações no estilo "tipos à esquerda", como int x = 0; As anotações de tipo

sempre vá atrás do que está sendo digitado.

Na maioria dos casos, porém, isso não é necessário. Sempre que possível, o TypeScript tenta inferir automaticamente
os tipos em seu código. Por exemplo, o tipo de uma variável é inferido com base no tipo de seu
inicializador:

// Nenhuma anotação de tipo necessária - 'myName' inferida como tipo 'string'


deixe meuNome = "Alice" ;

Na maior parte, você não precisa aprender explicitamente as regras de inferência. Se você está começando, tente
usando menos anotações de tipo do que você pensa - você pode se surpreender com o quão poucas você precisa para
TypeScript para entender completamente o que está acontecendo.

https://translate.googleusercontent.com/translate_f 15/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Funções
As funções são o meio principal de transmitir dados em JavaScript. TypeScript permite que você
especificar os tipos de valores de entrada e saída das funções.

Anotações de tipo de parâmetro

Quando você declara uma função, você pode adicionar anotações de tipo após cada parâmetro para declarar o que
tipos de parâmetros que a função aceita. As anotações de tipo de parâmetro vêm após o nome do parâmetro:

// Anotação do tipo de parâmetro


função saudação ( nome : string ) {
console . log ( "Olá," + nome . toUpperCase () + "!!" );
}

Quando um parâmetro tem uma anotação de tipo, os argumentos para essa função serão verificados:

// Seria um erro de tempo de execução se executado!


cumprimentar ( 42 );

O
O argumento
argumento do
do tipo
tipo 'número'
'número' não
não épode
atribuível
ser atribuído
ao parâmetro
ao parâmetro
do tipo do tipo 'string'.
'fragmento'.

Página 21

Mesmo se você não tiver anotações de tipo em seus parâmetros, o TypeScript ainda verificará se você passou no

número certo de argumentos.

Anotações de tipo de retorno

Você também pode adicionar anotações de tipo de retorno. As anotações de tipo de retorno aparecem após a lista de parâmetros:

function getFavoriteNumber (): number {


return 26 ;
}

Muito parecido com as anotações de tipo de variável, você geralmente não precisa de uma anotação de tipo de retorno porque
O TypeScript inferirá o tipo de retorno da função com base em suas instruções de retorno . O tipo
a anotação no exemplo acima não muda nada. Algumas bases de código especificarão explicitamente um
tipo de retorno para fins de documentação, para evitar alterações acidentais, ou apenas para uso pessoal
preferência.

Funções anônimas

As funções anônimas são um pouco diferentes das declarações de funções. Quando uma função aparece
em um lugar onde o TypeScript pode determinar como será chamado, os parâmetros desse
função recebem tipos automaticamente.

Aqui está um exemplo:

https://translate.googleusercontent.com/translate_f 16/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 22

// Nenhuma anotação de tipo aqui, mas o TypeScript pode detectar o bug


nomes const = [ "Alice" , "Bob" , "Eva" ];

// Tipagem contextual para função


nomes . forEach ( função ( ões ) {
console . log ( s . toUppercase ());

A
A propriedade
propriedade 'toUppercase'
'toUppercase' não
não existe
existe no
no tipo
tipo 'string'.
'string'. Você
Você quis
quis dizer
dizer
'toUpperCase'?
'toUpperCase'?

});

// A digitação contextual também se aplica a funções de seta


nomes . forEach ( s ) => {
console . log ( s . toUppercase ());

A
A propriedade
propriedade 'toUppercase'
'toUppercase' não
não existe
existe no
no tipo
tipo 'string'.
'string'. Você
Você quis
quis dizer
dizer
'toUpperCase'?
'toUpperCase'?

});

Mesmo que o parâmetro s não tenha uma anotação de tipo, o TypeScript usou os tipos do

função forEach , junto com o tipo inferido da matriz, para determinar o tipo que s terá.

Este processo é chamado de tipagem contextual porque o contexto em que a função ocorreu
informa que tipo deve ter.

Semelhante às regras de inferência, você não precisa aprender explicitamente como isso acontece, mas
compreender que isso acontece pode ajudá-lo a perceber quando as anotações de tipo não são necessárias. Mais tarde,
veremos mais exemplos de como o contexto em que ocorre um valor pode afetar seu tipo.

Tipos de Objetos
Além dos primitivos, o tipo mais comum de tipo que você encontrará é um tipo de objeto. Isso se refere
a qualquer valor JavaScript com propriedades, que são quase todos eles! Para definir um tipo de objeto, nós
simplesmente liste suas propriedades e seus tipos.

Por exemplo, aqui está uma função que usa um objeto semelhante a um ponto:

https://translate.googleusercontent.com/translate_f 17/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 23

// A anotação de tipo do parâmetro é um tipo de objeto


função printCoord ( pt : { x : número ; y : número }) {
console . log ( "O valor x da coordenada é" + pt . x );
console . log ( "O valor y da coordenada é" + pt . y );
}
printCoord ({ x: 3 , y: 7 });

Aqui, nós anotado o parâmetro com um tipo com duas propriedades - x e y - que são ambos
digite o número . Você pode usar , ou ; para separar as propriedades, e o último separador é opcional
de qualquer jeito.

A parte do tipo de cada propriedade também é opcional. Se você não especificar um tipo, será considerado
qualquer .

Propriedades Opcionais

Os tipos de objeto também podem especificar que algumas ou todas as suas propriedades são opcionais. Para fazer isso, adicione um ?
após o nome da propriedade:

function printName ( obj : { first : string ; last ?: string }) {


// ...
}
// Ambos tudo bem
printName ({ primeiro: "Bob" });
printName ({ primeiro: "Alice" , último: "Alisson" });

Em JavaScript, se você acessar uma propriedade que não existe, você obterá o valor undefined em vez de
um erro de tempo de execução. Por isso, ao ler uma propriedade opcional, você terá que verificar
indefinido antes de usá-lo.

Página 24

function printName ( obj : { first : string ; last ?: string }) {


// Erro - pode falhar se 'obj.last' não foi fornecido!
console . log ( obj . último . toUpperCase ());

O
O objeto
objeto éé possivelmente
possivelmente 'indefinido'.
'indefinido'.

if ( obj . last ! == undefined ) {


// OK
console . log ( obj . último . toUpperCase ());
}

// Uma alternativa segura usando a sintaxe JavaScript moderna:

https://translate.googleusercontent.com/translate_f 18/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

console . log ( obj . último ?. toUpperCase ());


}

Tipos de União
O sistema de tipos do TypeScript permite que você crie novos tipos a partir dos existentes usando uma grande variedade de
operadores. Agora que sabemos como escrever alguns tipos, é hora de começar a combiná-los em
maneiras interessantes.

Definindo um Tipo de União

A primeira maneira de combinar tipos que você pode ver é um tipo de união. Um tipo de união é um tipo formado a partir de
dois ou mais outros tipos, representando valores que podem ser qualquer um desses tipos. Nos referimos a cada
desses tipos como membros do sindicato.

Vamos escrever uma função que pode operar em strings ou números:

Página 25

function printId ( id : number | string ) {


console . log ( "Seu ID é:" + id );
}
// OK
printId ( 101 );
// OK
printId ( "202" );
// Error
printId ({ myID: 22342 });

Argumento
Argumento do
do tipo
tipo '{myID:
'{myID: number;
number; }} 'não
'não éé atribuível
atribuível ao
ao parâmetro
parâmetro de
de
tipo
tipo 'string
'string || número'.
número'.
Digite
Digite '{myID:
'{myID: número;
número; }} 'não
'não pode
pode ser
ser atribuído
atribuído ao
ao tipo'
tipo' número
número '.'.

Trabalhando com Tipos de União

É fácil fornecer um valor que corresponda a um tipo de união - basta fornecer um tipo que corresponda a qualquer um dos
membros do sindicato. Se você tem um valor do tipo sindical, como você trabalha com isso?

O TypeScript só permitirá que você faça coisas com o sindicato se isso for válido para todos os membros do
a União. Por exemplo, se você tiver a string de união | número , você não pode usar métodos que são
disponível apenas na string :

https://translate.googleusercontent.com/translate_f 19/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
function printId ( id : number | string ) {
console . log ( id . toUpperCase ());

A
A propriedade
propriedade 'toUpperCase'
'toUpperCase' não
não existe
existe no
no tipo
tipo 'string
'string || número'.
número'.
A
A propriedade
propriedade 'toUpperCase'
'toUpperCase' não
não existe
existe no
no tipo
tipo 'number'.
'number'.

A solução é estreitar a união com o código, da mesma forma que faria em JavaScript sem tipo
anotações. O estreitamento ocorre quando o TypeScript pode deduzir um tipo mais específico para um valor baseado
na estrutura do código.

Por exemplo, o TypeScript sabe que apenas um valor de string terá um valor typeof "string" :

Página 26

function printId ( id : number | string ) {


if ( id typeof === "string" ) {
// Neste ramo, id é do tipo 'string'
console . log ( id . toUpperCase ());
} else {
// Aqui, id é do tipo 'número'
console . log ( id );
}
}

Outro exemplo é usar uma função como Array.isArray :

function welcomePeople ( x : string [] | string ) {


if ( Array . isArray ( x )) {
// Aqui: 'x' é 'string []'
console . log ( "Olá," + x . join ( "e" ));
} else {
// Aqui: 'x' é 'string'
console . log ( "Bem-vindo viajante solitário" + x );
}
}

Observe que no outro ramo, não precisamos fazer nada de especial - se x não fosse uma string [] ,
então deve ter sido uma corda .

Às vezes, você terá um sindicato onde todos os membros têm algo em comum. Por exemplo,
ambos os arrays e strings têm um método slice . Se cada membro de um sindicato tiver uma propriedade em
comum, você pode usar essa propriedade sem restringir:

// O tipo de retorno é inferido como número [] | fragmento


function getFirstThree ( x : number [] | string ) {
return x . fatia ( 0 , 3 );
}

https://translate.googleusercontent.com/translate_f 20/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Pode ser confuso que uma união de tipos pareça ter a interseção das propriedades desses tipos. Esse
não é um acidente - o nome união vem da teoria dos tipos. O número do sindicato | string é

composto pela união dos valores de cada tipo. Observe que dados dois conjuntos com correspondentes

Página 27
fatos sobre cada conjunto, apenas a interseção desses fatos se aplica à união dos próprios conjuntos. Para

por exemplo, se tivéssemos uma sala com pessoas altas usando chapéus, e outra sala com pessoas que falavam espanhol usando

chapéus, depois de combinar esses quartos, a única coisa que sabemos sobre cada pessoa é que eles devem ser

usando um chapéu.

Digite aliases
Temos usado tipos de objeto e tipos de união, escrevendo-os diretamente nas anotações de tipo. Isto é
conveniente, mas é comum querer usar o mesmo tipo mais de uma vez e se referir a ele por um único
nome.

Um apelido de tipo é exatamente isso - um nome para qualquer tipo. A sintaxe de um alias de tipo é:

tipo Point = {
x : número ;
y : número ;
};

// Exatamente igual ao exemplo anterior


function printCoord ( pt : Point ) {
console . log ( "O valor x da coordenada é" + pt . x );
console . log ( "O valor y da coordenada é" + pt . y );
}

printCoord ({ x: 100 , y: 100 });

Na verdade, você pode usar um alias de tipo para dar um nome a qualquer tipo, não apenas a um tipo de objeto. Para
exemplo, um alias de tipo pode nomear um tipo de união:

tipo ID = número | string ;

Observe que apelidos são apenas apelidos - você não pode usar apelidos de tipo para criar "versões" diferentes / distintas
do mesmo tipo. Quando você usa o alias, é exatamente como se você tivesse escrito o tipo de alias. Em outro
palavras, este código pode parecer ilegal, mas está OK de acordo com o TypeScript porque ambos os tipos são apelidos
para o mesmo tipo:

Página 28

tipo UserInputSanitizedString = string ;

function sanitizeInput ( str : string ): UserInputSanitizedString {


retornar higienizar ( str );
}

https://translate.googleusercontent.com/translate_f 21/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
// Crie uma entrada higienizada
deixe userInput = sanitizeInput ( getInput ());

// No entanto, ainda pode ser reatribuído com uma string


userInput = "nova entrada" ;

Interfaces
Uma declaração de interface é outra maneira de nomear um tipo de objeto:

interface Point {
x : número ;
y : número ;
}

function printCoord ( pt : Point ) {


console . log ( "O valor x da coordenada é" + pt . x );
console . log ( "O valor y da coordenada é" + pt . y );
}

printCoord ({ x: 100 , y: 100 });

Assim como quando usamos um alias de tipo acima, o exemplo funciona como se tivéssemos usado um nome anônimo
Tipo de objeto. O TypeScript está preocupado apenas com a estrutura do valor que passamos para printCoord
- importa apenas que tenha as propriedades esperadas. Estar preocupado apenas com a estrutura e
recursos de tipos é o motivo pelo qual chamamos TypeScript de sistema de tipos estruturalmente tipado.

Diferenças entre apelidos de tipo e interfaces

Os apelidos de tipo e as interfaces são muito semelhantes e, em muitos casos, você pode escolher entre eles livremente.
Quase todos os recursos de uma interface estão disponíveis em tipo , a principal diferença é que um tipo
não pode ser reaberto para adicionar novas propriedades em vez de uma interface que é sempre extensível.

Página 29
Interface Modelo

Estendendo uma interface Extensão de um tipo por meio de interseções

interface Animal { tipo Animal = {


nome: string nome: string
} }

interface Bear extends Animal { tipo Bear = Animal & {


mel: booleano mel: booleano
} }

const bear = getBear () const bear = getBear ();


bear.name bear.name;
bear.honey bear.honey;

Adicionando novos campos a uma interface existente Um tipo não pode ser alterado após ser criado

https://translate.googleusercontent.com/translate_f 22/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

interface Window { tipo Window = {


título: string título: string
} }

interface Window { tipo Window = {


ts: TypeScriptAPI ts: TypeScriptAPI
} }

const src = 'const a = "Olá, Mundo"'; // Erro: identificador duplicado 'Windo


window.ts.transpileModule (src, {});

Você aprenderá mais sobre esses conceitos nos capítulos posteriores, então não se preocupe se não entender todos
destes imediatamente.

Antes do TypeScript versão 4.2, digite os nomes de alias pode aparecer em mensagens de erro, às vezes em
lugar do tipo anônimo equivalente (que pode ou não ser desejável). Interfaces irão
sempre ser nomeado em mensagens de erro.

Página 30
Os aliases de tipo não podem participar na declaração de fusão, mas as interfaces podem .

As interfaces só podem ser usadas para declara as formas dos objetos, não renomeia os primitivos .

Nomes de interface irão sempre aparecem em sua forma original nas mensagens de erro, mas apenas quando
são usados ​pelo nome.

Na maior parte, você pode escolher com base na preferência pessoal, e o TypeScript dirá se
precisa de algo para ser o outro tipo de declaração. Se você gostaria de uma heurística, use a interface
até que você precise usar recursos do tipo .

Asserções de tipo
Às vezes, você terá informações sobre o tipo de valor que o TypeScript não pode conhecer.

Por exemplo, se você estiver usando document.getElementById , o TypeScript só sabe que isso irá
retornar algum tipo de HTMLElement , mas você deve saber que sua página sempre terá um

HTMLCanvasElement com um determinado ID.

Nessa situação, você pode usar uma declaração de tipo para especificar um tipo mais específico:

const myCanvas = document . getElementById ( "main_canvas" ) como HTMLCanvasEleme

Como uma anotação de tipo, as asserções de tipo são removidas pelo compilador e não afetam o tempo de execução
comportamento do seu código.

Você também pode usar a sintaxe de colchetes angulares (exceto se o código estiver em um arquivo .tsx ), que é equivalente:

const myCanvas = documento < HTMLCanvasElement > . getElementById ( "main_canvas" )

Lembrete: como as asserções de tipo são removidas em tempo de compilação, não há verificação de tempo de execução associada

com uma declaração de tipo. Não haverá uma exceção ou nulo gerado se a asserção de tipo estiver errada.

https://translate.googleusercontent.com/translate_f 23/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

O TypeScript permite apenas declarações de tipo que se convertem em uma versão mais específica ou menos específica de um
modelo. Esta regra evita coerções "impossíveis" como:

Página 31

const x = "olá" como número ;

A
A conversão
conversão do
do tipo
tipo 'string'
'string' para
para 'número'
'número' pode
pode ser
ser um
um erro
erro porque
porque
nenhum
nenhum tipo
tipo se
se sobrepõe
sobrepõe suficientemente
suficientemente ao
ao outro.
outro. Se
Se isso
isso fosse
fosse
intencional,
intencional, converta
converta aa expressão
expressão para
para 'desconhecido'
'desconhecido' primeiro.
primeiro.

Às vezes, essa regra pode ser muito conservadora e não permitirá coerções mais complexas que podem
seja válido. Se isso acontecer, você pode usar duas asserções, primeiro para qualquer (ou desconhecido , que iremos
apresentar mais tarde), então para o tipo desejado:

const a = ( expr como qualquer ) como T ;

Tipos literais
Além dos tipos gerais de string e número , podemos nos referir a strings e números específicos
em posições de tipo.

Uma maneira de pensar sobre isso é considerar como o JavaScript vem com diferentes maneiras de declarar um
variável. Tanto var quanto let permitem alterar o que é mantido dentro da variável, e const faz
não. Isso se reflete em como o TypeScript cria tipos para literais.

let changingString = "Hello World" ;


changingString = "Olá Mundo" ;
// Porque `changingString` pode representar qualquer string possível, que
// é como o TypeScript o descreve no sistema de tipos
changingString ;

deixe changingString: string

const constantString = "Olá, mundo" ;


// Como `constantString` só pode representar 1 string possível,
// tem uma representação de tipo literal
constantString ;

const constantString: "Hello World"

Página 32
Por si só, os tipos literais não são muito valiosos:

https://translate.googleusercontent.com/translate_f 24/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

deixe x : "olá" = "olá" ;


// OK
x = "olá" ;
// ...
x = "howdy" ;

O
O tipo
tipo '"howdy"'
'"howdy"' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo '"hello"'.
'"hello"'.

Não adianta muito ter uma variável que só pode ter um valor!

Mas, combinando literais em uniões, você pode expressar um conceito muito mais útil - por exemplo,
funções que aceitam apenas um determinado conjunto de valores conhecidos:

function printText ( s : string , alinhamento : "esquerda" | "direita" | "centro" ) {


// ...
}
printText ( "Olá, mundo" , "esquerda" );
printText ( "G'day, mate" , "center" );

O
O argumento
argumento do
do tipo
tipo '"center"'
'"centro"' não
não éé atribuível
atribuível ao
ao parâmetro
parâmetro do
do tipo
tipo '"esquerda"
'"esquerda"
| "certo" | "Centro"'.
| "certo" | "Centro"'.

Os tipos literais numéricos funcionam da mesma maneira:

função compare ( a : string , b : string ): - 1 | 0 | 1 {


retornar a === b ? 0 : a > b ? 1 : -1 ;
}

Claro, você pode combiná-los com tipos não literais:

Página 33

Opções de interface {
largura : número ;
}
função configurar ( x : Opções | "auto" ) {
// ...
}
configurar ({ largura: 100 });
configure ( "auto" );
configurar ( "automático" );

O
O argumento
argumento do
do tipo
tipo '"automático"'
'"automático"' não
não pode
pode ser
ser atribuído
atribuído ao
ao parâmetro
parâmetro do
do tipo
tipo
'Opções
'Opções || "auto"'.
"auto"'.

Existe mais um tipo de tipo literal: literais booleanos. Existem apenas dois tipos literais booleanos, e
como você pode imaginar, eles são os tipos verdadeiro e falso . O próprio tipo booleano é, na verdade, apenas
https://translate.googleusercontent.com/translate_f 25/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

um pseudônimo para o sindicato true | falso .

Inferência literal

Quando você inicializa uma variável com um objeto, o TypeScript assume que as propriedades desse objeto
pode alterar os valores posteriormente. Por exemplo, se você escreveu um código como este:

const obj = { contador: 0 };


if ( alguma condição ) {
obj . contador = 1 ;
}

O TypeScript não assume que a atribuição de 1 a um campo que anteriormente tinha 0 é um erro.
Outra maneira de dizer isso é que obj.counter deve ter o número do tipo , não 0 , porque
tipos são usados ​para determinar o comportamento de leitura e gravação.

O mesmo se aplica a strings:

const req = { url: "https://example.com" , método: "GET" };


handleRequest ( req . url , req . método );

O
O argumento
argumento do
do tipo
tipo 'string'
'string' não
não éé atribuível
atribuível ao
ao parâmetro
parâmetro do
do tipo
tipo '"GET"
'"GET" |
|"PUBLICAR"'.
"PUBLICAR"'.

Página 34
No exemplo acima, req.method é inferido como string , não "GET" . Porque o código pode ser
avaliada entre a criação de req e a chamada de handleRequest que poderia atribuir um novo
string como "GUESS" para req.method , o TypeScript considera este código como tendo um erro.

Existem duas maneiras de contornar isso.

1. Você pode alterar a inferência adicionando uma afirmação de tipo em qualquer um dos locais:

// Mudança 1:
const req = { url: "https://example.com" , método: "GET" as "GET" };
// Mudança 2
handleRequest ( req . url , req . método como "GET" );

A mudança 1 significa "Pretendo que req.method tenha sempre o tipo literal " GET " ",
impedindo a possível atribuição de "GUESS" a esse campo depois. A alteração 2 significa "eu sei
por outros motivos, esse req.method tem o valor "GET" ".

2. Você pode usar as const para converter todo o objeto em literais de tipo:

const req = { url: "https://example.com" , método: "GET" } como const ;


handleRequest ( req . url , req . método );

O sufixo as const atua como const, mas para o sistema de tipos, garantindo que todas as propriedades sejam
atribuído o tipo literal em vez de uma versão mais geral, como string ou número .

https://translate.googleusercontent.com/translate_f 26/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

nulo e indefinido
JavaScript tem dois valores primitivos usados ​para sinalizar valor ausente ou não inicializado: nulo e

indefinido .

TypeScript possui dois tipos correspondentes com os mesmos nomes. Como esses tipos se comportam depende de
se você tem o opção strictNullChecks ativada .

strictNullChecks off

Com strictNullChecks off, os valores que podem ser nulos ou indefinidos ainda podem ser acessados
normalmente, e os valores null e undefined podem ser atribuídos a uma propriedade de qualquer tipo. Isto é

Página 35
semelhante a como as linguagens sem verificações de nulos (por exemplo, C #, Java) se comportam. A falta de verificação para estes
os valores tendem a ser uma fonte importante de bugs; Nós sempre recomendamos que as pessoas voltem
strictNullChecks sobre se é prático fazer isso em sua base de código.

strictNullChecks on

Com strictNullChecks on, quando um valor é nulo ou indefinido , você precisará testar
esses valores antes de usar métodos ou propriedades nesse valor. Assim como verificar se há indefinido
antes de usar uma propriedade opcional, podemos usar o estreitamento para verificar os valores que podem ser nulos :

function doSomething ( x : string | null ) {


if ( x === null ) {
// fazer nada
} else {
console . log ( "Olá," + x . toUpperCase ());
}
}

Operador de asserção não nulo (Postfix ! )

TypeScript também tem uma sintaxe especial para remover null e undefined de um tipo sem
fazendo qualquer verificação explícita. Escrevendo ! após qualquer expressão é efetivamente uma afirmação de tipo que o
o valor não é nulo ou indefinido :

function liveDangerously ( x ?: number | null ) {


// Sem erro
console . log ( x !. toFixed ());
}

Assim como outras asserções de tipo, isso não muda o comportamento do tempo de execução do seu código, então é
importante usar apenas ! quando você sabe que o valor não pode ser nulo ou indefinido .

Enums
Enums são um recurso adicionado ao JavaScript pelo TypeScript que permite descrever um valor que
pode ser um de um conjunto de possíveis constantes nomeadas. Ao contrário da maioria dos recursos do TypeScript, este não é um
adição de nível de tipo ao JavaScript, mas algo adicionado à linguagem e ao tempo de execução. Por causa disso,

https://translate.googleusercontent.com/translate_f 27/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 36
é um recurso que você deve saber que existe, mas talvez deixe de usá-lo a menos que tenha certeza. Vocês
pode ler mais sobre enums no Página de referência de Enum.

Primitivos menos comuns


Vale a pena mencionar o resto das primitivas em JavaScript que são representadas no tipo
sistema. Embora não vamos entrar em detalhes aqui.

bigint

De ES2020 em diante, existe uma primitiva em JavaScript usada para inteiros muito grandes, BigInt :

// Criação de um bigint por meio da função BigInt


const oneHundred : bigint = BigInt ( 100 );

// Criação de um BigInt por meio da sintaxe literal


const anotherHundred : bigint = 100 n ;

Você pode aprender mais sobre o BigInt em as notas de versão do TypeScript 3.2.

símbolo

Existe um primitivo em JavaScript usado para criar uma referência globalmente única por meio da função
Símbolo () :

const firstName = Symbol ( "nome" );


const secondName = Symbol ( "nome" );

if ( firstName === secondName ) {

Esta
Esta condição
condição sempre
sempre retornará
retornará 'falso',
'falso', pois
pois os
os tipos
tipos 'typeof
'typeof
firstName
firstName 'e'
'e' typeof
typeof secondName
secondName 'não
'não se
se sobrepõem.
sobrepõem.

// Nunca pode acontecer


}

Você pode aprender mais sobre eles em Página de referência de símbolos.

Página 37

Estreitando

Imagine que temos uma função chamada padLeft .

function padLeft ( padding : number | string , input : string ): string {


lançar novo erro ( "Ainda não implementado!" );
}

https://translate.googleusercontent.com/translate_f 28/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Se o preenchimento for um número , ele o tratará como o número de espaços que desejamos adicionar antes da entrada . Se

o preenchimento é uma string , ele deve apenas preceder o preenchimento à entrada . Vamos tentar implementar a lógica
para quando padLeft recebe um número para preenchimento .

function padLeft ( padding : number | string , input : string ) {


retornar "" . repetir ( preenchimento ) + entrada ;

Argumento
Argumento do
do tipo
tipo 'string
'string || número
número 'não
'não éé atribuível
atribuível ao
ao parâmetro
parâmetro de
do tipo
digite
'número'.
'número'.
O
O tipo
tipo 'string'
'string' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo 'número'.
'número'.

Ups, estamos obtendo um erro no preenchimento . O TypeScript está nos avisando que adicionar um número a um

número | string pode não nos dar o que queremos, e está certo. Em outras palavras, não temos
verificado explicitamente se o preenchimento é um número primeiro, nem estamos lidando com o caso em que é uma string ,
então vamos fazer exatamente isso.

function padLeft ( padding : number | string , input : string ) {


if ( typeof padding === "número" ) {
retornar "" . repetir ( preenchimento ) + entrada ;
}
retorno de preenchimento + entrada ;
}

Se isso se parece principalmente com um código JavaScript desinteressante, esse é o ponto. Apesar de
anotações que colocamos no lugar, este código TypeScript se parece com JavaScript. A ideia é que o TypeScript

Página 38
sistema de tipos tem como objetivo tornar o mais fácil possível escrever código JavaScript típico sem dobrar
ao contrário para obter segurança de tipo.

Embora possa não parecer muito, na verdade há muita coisa acontecendo nos bastidores aqui. Muito parecido com como
O TypeScript analisa os valores de tempo de execução usando tipos estáticos, sobrepõe a análise de tipo em JavaScript
construções de fluxo de controle de tempo de execução como if / else , ternários condicionais, loops, verificações de veracidade, etc.,
que podem afetar todos esses tipos.

Em nossa verificação if , o TypeScript vê typeof padding === "número" e entende isso como um
forma especial de código chamada de proteção de tipo. TypeScript segue possíveis caminhos de execução que nosso
programas podem levar para analisar o tipo mais específico possível de um valor em uma determinada posição. Parece
nessas verificações especiais (chamadas de guardas de tipo) e atribuições, e o processo de refinar tipos para
tipos mais específicos do que os declarados são chamados de estreitamento. Em muitos editores, podemos observar esses tipos
conforme eles mudam, e faremos isso em nossos exemplos.

function padLeft ( padding : number | string , input : string ) {


if ( typeof padding === "número" ) {
retornar "" . repetir ( preenchimento ) + entrada ;

(parâmetro) preenchimento: número

}
retorno de preenchimento + entrada ;

(parâmetro) preenchimento: string

https://translate.googleusercontent.com/translate_f 29/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Existem algumas construções diferentes que o TypeScript entende para estreitamento.

typeof guardas tipo


Como vimos, o JavaScript suporta um operador typeof que pode fornecer informações muito básicas sobre
o tipo de valores que temos em tempo de execução. O TypeScript espera que isso retorne um determinado conjunto de strings:

"fragmento"

"número"

"bigint"

"boleano"

Página 39
"símbolo"

"Indefinido"

"objeto"

"função"

Como vimos com padLeft , esse operador aparece com bastante frequência em várias bibliotecas JavaScript,
e o TypeScript pode entendê-lo para restringir tipos em diferentes ramos.

No TypeScript, verificar o valor retornado por typeof é uma proteção de tipo. Porque TypeScript
codifica como typeof opera em diferentes valores, ele conhece algumas de suas peculiaridades em JavaScript.
Por exemplo, observe que na lista acima, typeof não retorna a string nula . Confira o
seguinte exemplo:

function printAll ( strs : string | string [] | null ) {


if ( typeof strs === "objeto" ) {
para ( const s de strs ) {

O
O objeto
objeto éé possivelmente
possivelmente 'nulo'.
'nulo'.

console . log ( s );
}
} else if ( typeof strs === "string" ) {
console . log ( strs );
} else {
// fazer nada
}
}

Na função printAll , tentamos verificar se strs é um objeto para ver se é um tipo de array (agora
pode ser um bom momento para reforçar que os arrays são tipos de objeto em JavaScript). Mas acontece que em
JavaScript, typeof null é na verdade "objeto" ! Este é um daqueles infelizes acidentes de
história.

Usuários com experiência suficiente podem não se surpreender, mas nem todos se depararam com isso em
JavaScript; felizmente, o TypeScript nos permite saber que strs foi reduzido apenas para string [] |

null em vez de apenas string [] .

Isso pode ser uma boa transição para o que chamaremos de verificação de "veracidade".

https://translate.googleusercontent.com/translate_f 30/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Estreitamento da verdade

Página 40
Verdade pode não ser uma palavra que você encontrará no dicionário, mas é muito algo que você
ouvir sobre em JavaScript.

Em JavaScript, podemos usar qualquer expressão em condicionais, && s, || declarações s, if , Boolean


negações ( ! ) e muito mais. Por exemplo, as declarações if não esperam que sua condição sempre
tem o tipo booleano .

function getUsersOnlineMessage ( numUsersOnline : number ) {


if ( numUsersOnline ) {
return `Existem $ { numUsersOnline } online agora!` ;
}
return "Ninguém está aqui. :(" ;
}

Em JavaScript, construções como se primeiro "forcem" suas condições aos booleanos para dar sentido a elas,
e então escolher seus ramos dependendo se o resultado é verdadeiro ou falso . Valores como

NaN

"" (a string vazia)

0n (a versão bigint de zero)

nulo

Indefinido

todos são coagidos a falsos , e outros valores tornam-se verdadeiros coagidos . Você sempre pode forçar valores a

boolean s executando-os por meio da função booleana ou usando o método duplo mais curto
Negação booleana. (O último tem a vantagem de que o TypeScript infere um tipo booleano literal estreito
verdadeiro , enquanto infere o primeiro como tipo booleano .)

// ambos resultam em 'verdadeiro'


Boolean ( "olá" ); // tipo: booleano, valor: verdadeiro
!! "mundo" ; // tipo: verdadeiro, valor: verdadeiro

É bastante comum aproveitar esse comportamento, especialmente para se proteger contra valores como null ou

indefinido . Como exemplo, vamos tentar usá-lo para nossa função printAll .

Página 41

function printAll ( strs : string | string [] | null ) {


if ( strs && typeof strs === "objeto" ) {
para ( const s de strs ) {
console . log ( s );
}
} else if ( typeof strs === "string" ) {
console . log ( strs );

https://translate.googleusercontent.com/translate_f 31/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

}
}

Você notará que nos livramos do erro acima verificando se strs é verdadeiro. Pelo menos isso
nos impede de erros temidos quando executamos nosso código como:

TypeError: null não é iterável

Lembre-se, porém, de que a verificação de veracidade em primitivas pode frequentemente estar sujeita a erros. Como um
exemplo, considere uma tentativa diferente de escrever printAll

function printAll ( strs : string | string [] | null ) {


// !!!!!!!!!!!!!!!!!
// NÃO FAÇA ISSO!
// CONTINUE LENDO
// !!!!!!!!!!!!!!!!!
if ( strs ) {
if ( typeof strs === "objeto" ) {
para ( const s de strs ) {
console . log ( s );
}
} else if ( typeof strs === "string" ) {
console . log ( strs );
}
}
}

Envolvemos todo o corpo da função em uma verificação verdadeira, mas isso tem uma desvantagem sutil: nós
pode não estar mais manipulando a caixa de string vazia corretamente.

Página 42
TypeScript não nos prejudica em nada, mas este é um comportamento que vale a pena observar se você não estiver familiarizado com
JavaScript. O TypeScript pode frequentemente ajudá-lo a detectar bugs no início, mas se você optar por não fazer nada com
um valor, há muito que ele pode fazer sem ser excessivamente prescritivo. Se você quiser você pode
certifique-se de lidar com situações como essas com um linter.

Uma última palavra sobre o estreitamento pela veracidade é que as negações booleanas com ! filtrar de negado
galhos.

function multiplyAll (
valores : número [] | indefinido ,
fator : número
): número [] | undefined {
if (! valores ) {
valores de retorno ;
} else {
valores de retorno . map (( x ) => x * fator );
}
}

Estreitamento de igualdade
https://translate.googleusercontent.com/translate_f 32/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Typescript também usa mudar declarações e verificações de igualdade como === , ! == , == e ! = A


tipos estreitos. Por exemplo:

Página 43

exemplo de função ( x : string | número , y : string | booleano ) {


if ( x === y ) {
// Agora podemos chamar qualquer método 'string' em 'x' ou 'y'.
x . toUpperCase ();

(método) String.toUpperCase (): string

y . toLowerCase ();

(método) String.toLowerCase (): string

} else {
console . log ( x );

(parâmetro) x: string | número

console . log ( y );

(parâmetro) y: string | boleano

}
}

Quando verificamos que x e y são iguais no exemplo acima, o TypeScript conhecia seus tipos
também tinha que ser igual. Uma vez que string é o único tipo comum que tanto x quanto y podem assumir,
O TypeScript sabe que x e y devem ser uma string na primeira ramificação.

Verificar valores literais específicos (em oposição a variáveis) também funciona. Em nossa seção sobre
estreitando a veracidade , escrevemos uma função printAll que estava sujeita a erros porque
acidentalmente não manipulou strings vazias corretamente. Em vez disso, poderíamos ter feito uma verificação específica para
bloqueie os nulos e o TypeScript ainda removerá corretamente o nulo do tipo de strs .

https://translate.googleusercontent.com/translate_f 33/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 44

function printAll ( strs : string | string [] | null ) {


if ( strs ! == null ) {
if ( typeof strs === "objeto" ) {
para ( const s de strs ) {

(parâmetro) strs: string []

console . log ( s );
}
} else if ( typeof strs === "string" ) {
console . log ( strs );

(parâmetro) strs: string

}
}
}

As verificações de igualdade mais frouxas do JavaScript com == e ! = Também são reduzidas corretamente. Se vocês são
desconhecido, verificar se algo == null realmente não apenas verifica se é especificamente
o valor null - também verifica se é potencialmente indefinido . O mesmo se aplica a ==

undefined : verifica se um valor é nulo ou indefinido .

interface Container {
valor : número | null | indefinido ;
}

function multiplyValue ( container : Container , fator : número ) {


// Remova 'null' e 'undefined' do tipo.
if ( container . valor ! = null ) {
console . log ( recipiente . valor );

(propriedade) Container.value: number

// Agora podemos multiplicar com segurança 'container.value'.


recipiente . valor * = fator ;
}
}

Página 45

O no estreitamento operador

https://translate.googleusercontent.com/translate_f 34/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
JavaScript tem um operador para determinar se um objeto tem uma propriedade com um nome: o em
operador. O TypeScript leva isso em consideração como uma forma de restringir os tipos potenciais.

Por exemplo, com o código: "valor" em x . onde "valor" é uma string literal ex é uma união
modelo. O ramo "verdadeiro" restringe os tipos de x que têm uma propriedade opcional ou obrigatória

valor , e a ramificação "falsa" restringe-se a tipos que têm uma propriedade opcional ou ausente
valor .

tipo Peixe = { nadar : () => void };


tipo Bird = { fly : () => void };

função mover ( animal : Peixe | Pássaro ) {


if ( "nadar" no animal ) {
animal de retorno . nadar ();
}

animal de retorno . voar ();


}

Para reiterar, as propriedades opcionais existirão em ambos os lados para o estreitamento, por exemplo, um humano poderia
tanto nadar e voar (com o equipamento certo) e, portanto, deve mostrar-se em ambos os lados da em
Verifica:

Página 46

tipo Peixe = { nadar : () => void };


tipo Bird = { fly : () => void };
tipo Humano = { nadar ?: () => vazio ; voar ?: () => void };

função mover ( animal : Peixe | Pássaro | Humano ) {


if ( "nadar" no animal ) {
animal ;

(parâmetro) animal: Peixe | Humano

} else {
animal ;

(parâmetro) animal: Bird | Humano

}
}

https://translate.googleusercontent.com/translate_f 35/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

instância de estreitamento
JavaScript tem um operador para verificar se um valor é ou não uma "instância" de outro valor.
Mais especificamente, em JavaScript x instanceof Foo verifica se a cadeia de protótipo de x
contém Foo.prototype . Embora não vamos mergulhar fundo aqui, você verá mais disso quando chegarmos
em classes, eles ainda podem ser úteis para a maioria dos valores que podem ser construídos com new . Como você pode
adivinhou, instanceof também é um protetor de tipo, e TypeScript estreita em ramos protegidos por

instanceof s.

function logValue ( x : Date | string ) {


if ( x instância de Data ) {
console . log ( x . toUTCString ());

(parâmetro) x: Data

} else {
console . log ( x . toUpperCase ());

(parâmetro) x: string

}
}

Página 47

atribuições
Como mencionamos anteriormente, quando atribuímos a qualquer variável, o TypeScript olha para o lado direito do
atribuição e estreita o lado esquerdo de forma adequada.

deixe x = matemática . aleatório () < 0,5 ? 10 : "olá, mundo!" ;

deixe x: string | número

x=1;

console . log ( x );

deixe x: número

x = "adeus!" ;

console . log ( x );

deixe x: string

Observe que cada uma dessas atribuições é válida. Mesmo que o tipo observado de x mudou para

número depois do nosso primeiro trabalho, ainda foram capazes de atribuir uma corda para x . Isso ocorre porque o
tipo declarado de x - o tipo com o qual x começou - é uma string | número , e atribuibilidade é
sempre verificado em relação ao tipo declarado.

Se tivéssemos atribuído um boolean para x , teríamos visto um erro, uma vez que não fazia parte da declarada
modelo.

https://translate.googleusercontent.com/translate_f 36/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 48

deixe x = matemática . aleatório () < 0,5 ? 10 : "olá, mundo!" ;

deixe x: string | número

x=1;

console . log ( x );

deixe x: número

x = verdadeiro ;

O
O tipo
tipo 'booleano'
'booleano' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo 'string
'string || número'.
número'.

console . log ( x );

deixe x: string | número

Análise de fluxo de controle


Até este ponto, vimos alguns exemplos básicos de como o TypeScript se restringe
ramos específicos. Mas há um pouco mais acontecendo do que apenas subir a partir de cada variável e
procurando por guardas de tipo em if s, while s, condicionais, etc. Por exemplo

function padLeft ( padding : number | string , input : string ) {


if ( typeof padding === "número" ) {
retornar "" . repetir ( preenchimento ) + entrada ;
}
retorno de preenchimento + entrada ;
}

padLeft retorna de seu primeiro bloco if . TypeScript foi capaz de analisar este código e ver
que o resto do corpo ( retorno de preenchimento + entrada; ) está inacessível no caso de preenchimento
é um número . Como resultado, ele foi capaz de remover o número do tipo de preenchimento (estreitamento
da corda | número para string ) para o resto da função.

Essa análise de código com base na acessibilidade é chamada de análise de fluxo de controle e o TypeScript usa isso
análise de fluxo para tipos estreitos à medida que encontra protetores de tipo e atribuições. Quando uma variável é

https://translate.googleusercontent.com/translate_f 37/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 49
analisado, o fluxo de controle pode se separar e fundir novamente uma e outra vez, e essa variável pode ser
observado ter um tipo diferente em cada ponto.

exemplo de função () {
deixe x : string | número | booleano ;

x = matemática . aleatório () < 0,5 ;

console . log ( x );

deixe x: booleano

if ( Math . random () < 0,5 ) {


x = "olá" ;
console . log ( x );

deixe x: string

} else {
x = 100 ;
console . log ( x );

deixe x: número

return x ;

deixe x: string | número

Usando predicados de tipo


Trabalhamos com construções JavaScript existentes para lidar com o estreitamento até agora, mas às vezes
você deseja um controle mais direto sobre como os tipos mudam em todo o código.

Para definir um protetor de tipo definido pelo usuário, simplesmente precisamos definir uma função cujo tipo de retorno é um tipo
predicado:

Página 50

function isFish ( pet : Fish | Bird ): pet is Fish {


retorno ( animal de estimação como Peixe ). nadar ! == indefinido ;
}

pet is Fish é nosso predicado de tipo neste exemplo. Um predicado assume a forma parameterName
é o tipo , onde parameterName deve ser o nome de um parâmetro da função atual
assinatura.

Sempre que isFish é chamado com alguma variável, o TypeScript restringirá essa variável para aquele específico
digite se o tipo original for compatível.

https://translate.googleusercontent.com/translate_f 38/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

// Ambas as chamadas para 'nadar' e 'voar' agora estão corretas.


let pet = getSmallPet ();

if ( isFish ( pet )) {
animal de estimação . nadar ();
} else {
animal de estimação . voar ();
}

Observe que o TypeScript não apenas sabe que pet é um Fish no ramo if ; ele também sabe que em
o outro ramo, você não tem um peixe , então você deve ter um pássaro .

Você pode usar o tipo guard isFish para filtrar uma matriz de Fish | Bird e obter uma série de

Peixe :

const zoo : ( Fish | Bird ) [] = [ getSmallPet (), getSmallPet (), getSmallPet ()]
const underWater1 : Fish [] = zoo . filtro ( isFish );
// ou equivalente
const underWater2 : Fish [] = zoo . filtrar ( isFish ) como Fish [];

// O predicado pode precisar ser repetido para exemplos mais complexos


const underWater3 : Fish [] = zoo . filtro (( animal de estimação ): animal de estimação é peixe => {
if ( pet . name === "sharkey" ) return false ;
return isFish ( animal de estimação );
});

Página 51
Além disso, as aulas podem use este é o tipo para restringir seu tipo.

Sindicatos discriminados
A maioria dos exemplos que vimos até agora concentrou-se no estreitamento de variáveis ​únicas com
tipos simples como string , booleano e número . Embora isso seja comum, na maioria das vezes em
Em JavaScript, lidaremos com estruturas um pouco mais complexas.

Para alguma motivação, vamos imaginar que estamos tentando codificar formas como círculos e quadrados. Círculos
acompanhe seus raios e quadrados, acompanhe seus comprimentos laterais. Usaremos um campo chamado
tipo para dizer com qual forma estamos lidando. Aqui está uma primeira tentativa de definir a Forma .

interface Shape {
tipo : "círculo" | "quadrado" ;
raio ?: número ;
sideLength ?: número ;
}

Observe que estamos usando uma união de tipos literais de string: "círculo" e "quadrado" para nos dizer se
deve tratar a forma como um círculo ou quadrado, respectivamente. Usando "círculo" | "quadrado" ao invés
de string , podemos evitar problemas de ortografia.

function handleShape ( shape : Shape ) {


// oops!

https://translate.googleusercontent.com/translate_f 39/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
if ( forma . tipo === "rect" ) {

Esta
Esta condição
condição sempre
sempre retornará
retornará 'falso',
'falso', pois
pois os
os tipos
tipos '"círculo"
'"círculo" ||
"square"
"square" 'e'
'e' "rect"
"rect" 'não
'não se
se sobrepõem.
sobrepõem.

// ...
}
}

Podemos escrever uma função getArea que aplica a lógica certa com base no fato de estar lidando com um círculo ou
quadrado. Vamos primeiro tentar lidar com círculos.

Página 52

function getArea ( shape : Shape ) {


voltar Math .PI * forma . raio ** 2 ;

O
O objeto
objeto éé possivelmente
possivelmente 'indefinido'.
'indefinido'.

Debaixo strictNullChecks que nos dá um erro - o que é apropriado, pois o raio pode não
ser definida. Mas e se executarmos as verificações apropriadas na propriedade kind ?

function getArea ( shape : Shape ) {


if ( forma . tipo === "círculo" ) {
voltar Math .PI * forma . raio ** 2 ;

O
O objeto
objeto éé possivelmente
possivelmente 'indefinido'.
'indefinido'.

}
}

Hmm, o TypeScript ainda não sabe o que fazer aqui. Chegamos a um ponto em que sabemos mais sobre
nossos valores do que o verificador de tipo. Poderíamos tentar usar uma afirmação não nula (a ! Após

shape.radius ) para dizer que radius está definitivamente presente.

function getArea ( shape : Shape ) {


if ( forma . tipo === "círculo" ) {
voltar Math .PI * forma . raio ! ** 2 ;
}
}

Mas isso não parece ideal. Tivemos que gritar um pouco com o verificador de tipo com essas afirmações não nulas
( ! ) para convencê-lo de que shape.radius foi definido, mas essas afirmações estão sujeitas a erros se começarmos
para mover o código. Além disso, fora destrictNullChecks que podemos acidentalmente
acessar qualquer um desses campos de qualquer maneira (uma vez que as propriedades opcionais são apenas consideradas como estando sempre presentes
ao lê-los). Definitivamente podemos fazer melhor.

O problema com esta codificação de Shape é que o verificador de tipo não tem como saber
se radius ou sideLength estão presentes ou não com base na propriedade kind . Nós precisamos

https://translate.googleusercontent.com/translate_f 40/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
comunicar o que sabemos ao verificador de tipo. Com isso em mente, vamos dar outra tacada
definindo a forma .

Página 53

interface Circle {
tipo : "círculo" ;
raio : número ;
}

interface Square {
tipo : "quadrado" ;
sideLength : número ;
}

tipo Forma = Círculo | Square ;

Aqui, separamos adequadamente o Shape em dois tipos com valores diferentes para o tipo
propriedade, mas radius e sideLength são declarados como propriedades obrigatórias em seus respectivos
tipos.

Vamos ver o que acontece aqui quando tentamos acessar o raio de uma forma .

function getArea ( shape : Shape ) {


voltar Math .PI * forma . raio ** 2 ;

A
A propriedade
propriedade 'radius'
'radius' não
não existe
existe no
no tipo
tipo 'Forma'.
'Forma'.
A
A propriedade
propriedade 'radius'
'radius' não
não existe
existe no
no tipo
tipo 'Square'.
'Square'.

Como em nossa primeira definição de Forma , isso ainda é um erro. Quando o raio era opcional, obtivemos um
erro (apenas em strictNullChecks) porque o TypeScript não conseguiu dizer se a propriedade era
presente. Agora que a forma é uma união, o TypeScript está nos dizendo que a forma pode ser um quadrado e

Os quadrados não têm raio definido neles! Ambas as interpretações estão corretas, mas apenas o nosso
nova codificação de Shape ainda causa um erro fora destrictNullChecks.

Mas e se tentássemos verificar a propriedade kind novamente?

Página 54

function getArea ( shape : Shape ) {


if ( forma . tipo === "círculo" ) {
voltar Math .PI * forma . raio ** 2 ;

(parâmetro) forma: Círculo

https://translate.googleusercontent.com/translate_f 41/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
}

Isso acabou com o erro! Quando cada tipo em uma união contém uma propriedade comum com tipos literais,
O TypeScript considera que é uma união discriminada e pode restringir os membros do
União.

Neste caso, kind era aquela propriedade comum (que é considerada uma propriedade discriminante
de forma ). Verificar se a propriedade kind era "circle" eliminou todos os tipos em Shape
que não tinha uma propriedade kind com o tipo "círculo" . Essa forma reduzida para o
digite Círculo .

A mesma verificação também funciona com as instruções switch . Agora podemos tentar escrever nosso completo

getArea sem nenhum incômodo ! asserções não nulas.

function getArea ( shape : Shape ) {


switch ( forma . tipo ) {
caso "círculo" :
voltar Math .PI * forma . raio ** 2 ;

(parâmetro) forma: Círculo

caso "quadrado" :
forma de retorno . sideLength ** 2 ;

(parâmetro) forma: Quadrado

}
}

O importante aqui era a codificação da Forma . Comunicar as informações certas para


TypeScript - que Circle e Square eram realmente dois tipos separados com campos de tipo específicos -
foi crucial. Fazendo isso, vamos escrever um código TypeScript de tipo seguro que não seja diferente do

Página 55
JavaScript que teríamos escrito de outra forma. A partir daí, o sistema de tipos foi capaz de fazer o "certo"
coisa e descobrir os tipos em cada ramo de nossa instrução switch .

Como um aparte, tente brincar com o exemplo acima e remova algumas das palavras-chave de retorno. Você vai

veja que a verificação de tipo pode ajudar a evitar bugs quando acidentalmente cair em diferentes cláusulas em um

declaração switch .

Uniões discriminadas são úteis para mais do que apenas falar sobre círculos e quadrados. Eles são bons
para representar qualquer tipo de esquema de mensagens em JavaScript, como ao enviar mensagens pelo
rede (comunicação cliente / servidor) ou codificação de mutações em uma estrutura de gerenciamento de estado.

O tipo nunca
Ao estreitar, você pode reduzir as opções de um sindicato a um ponto em que removeu todos
possibilidades e não tem mais nada. Nesses casos, o TypeScript usará um tipo never para representar um
estado que não deveria existir.

Verificação de exaustividade
O tipo never pode ser atribuído a todos os tipos; no entanto, nenhum tipo pode ser atribuído a nunca (exceto

https://translate.googleusercontent.com/translate_f 42/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
nunca em si). Isso significa que você pode usar o estreitamento e nunca aparecer para fazer
verificar em uma instrução switch.

Por exemplo, adicionar um padrão à nossa função getArea que tenta atribuir a forma a

nunca surgirá quando todos os casos possíveis não tiverem sido tratados.

tipo Forma = Círculo | Square ;

function getArea ( shape : Shape ) {


switch ( forma . tipo ) {
caso "círculo" :
voltar Math .PI * forma . raio ** 2 ;
caso "quadrado" :
forma de retorno . sideLength ** 2 ;
padrão :
const _exhaustiveCheck : nunca = forma ;
return _exhaustiveCheck ;
}
}

Página 56
Adicionar um novo membro à união da forma causará um erro de TypeScript:

interface Triangle {
tipo : "triângulo" ;
sideLength : número ;
}

tipo Forma = Círculo | Square | Triângulo ;

function getArea ( shape : Shape ) {


switch ( forma . tipo ) {
caso "círculo" :
voltar Math .PI * forma . raio ** 2 ;
caso "quadrado" :
forma de retorno . sideLength ** 2 ;
padrão :
const _exhaustiveCheck : nunca = forma ;

O
O tipo
tipo 'Triângulo'
'Triângulo' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo 'nunca'.
'nunca'.

return _exhaustiveCheck ;
}
}

https://translate.googleusercontent.com/translate_f 43/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 57

Mais sobre funções

As funções são o bloco de construção básico de qualquer aplicativo, sejam funções locais importadas
de outro módulo ou métodos em uma classe. Eles também são valores e, assim como outros valores,
O TypeScript tem muitas maneiras de descrever como as funções podem ser chamadas. Vamos aprender como escrever
tipos que descrevem funções.

Expressões de tipo de função


A maneira mais simples de descrever uma função é com uma expressão de tipo de função. Esses tipos são
sintaticamente semelhantes às funções de seta:

saudação de função ( fn : ( a : string ) => void ) {


fn ( "Olá, mundo" );
}

function printToConsole ( s : string ) {


console . log ( s );
}

saudação ( printToConsole );

A sintaxe (a: string) => void significa "uma função com um parâmetro, denominado a , do tipo
string, que não tem um valor de retorno ". Assim como com as declarações de função, se um tipo de parâmetro não for
especificado, é implicitamente qualquer .

Observe que o nome do parâmetro é obrigatório . O tipo de função (string) => void significa "uma função

com um parâmetro denominado string do tipo any "!

Claro, podemos usar um alias de tipo para nomear um tipo de função:

digite GreetFunction = ( a : string ) => void ;


função de guias ( fn : GreetFunction ) {
// ...
}

Página 58

Assinaturas de Chamada
Em JavaScript, as funções podem ter propriedades além de serem chamáveis. No entanto, o tipo de função

https://translate.googleusercontent.com/translate_f 44/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
a sintaxe da expressão não permite a declaração de propriedades. Se quisermos descrever algo que pode ser chamado
com propriedades, podemos escrever uma assinatura de chamada em um tipo de objeto:

tipo DescribableFunction = {
descrição : string ;
( someArg : número ): booleano ;
};
function doSomething ( fn : DescribableFunction ) {
console . log ( fn . descrição + "retornado" + fn ( 6 ));
}

Observe que a sintaxe é ligeiramente diferente em comparação com uma expressão de tipo de função - use : entre
a lista de parâmetros e o tipo de retorno em vez de => .

Construir Assinaturas
As funções JavaScript também podem ser chamadas com o novo operador. TypeScript se refere a eles como
construtores porque geralmente criam um novo objeto. Você pode escrever uma assinatura de construção por
adicionar a nova palavra-chave antes de uma assinatura de chamada:

tipo SomeConstructor = {
novo ( s : string ): SomeObject ;
};
function fn ( ctor : SomeConstructor ) {
retornar novo ctor ( "olá" );
}

Alguns objetos, como o objeto Date do JavaScript , podem ser chamados com ou sem new . Você pode combinar
chamar e construir assinaturas do mesmo tipo arbitrariamente:

interface CallOrConstruct {
novo ( s : string ): Data ;
( n ?: número ): número ;
}

Página 59

Funções Genéricas
É comum escrever uma função onde os tipos de entrada se relacionam com o tipo de saída, ou
onde os tipos de duas entradas estão relacionados de alguma forma. Vamos considerar por um momento uma função que
retorna o primeiro elemento de uma matriz:

function firstElement ( arr : any []) {


return arr [ 0 ];
}

Essa função faz seu trabalho, mas infelizmente tem o tipo de retorno any . Seria melhor se a função
retornou o tipo do elemento da matriz.

No TypeScript, os genéricos são usados ​quando queremos descrever uma correspondência entre dois valores.
Fazemos isso declarando um parâmetro de tipo na assinatura da função:

https://translate.googleusercontent.com/translate_f 45/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

função firstElement < Type > ( arr : Type []): Type | undefined {
return arr [ 0 ];
}

Adicionando um parâmetro de tipo Type a esta função e usando-o em dois lugares, criamos um link
entre a entrada da função (a matriz) e a saída (o valor de retorno). Agora, quando chamamos,
surge um tipo mais específico:

// s é do tipo 'string'
const s = firstElement ([ "a" , "b" , "c" ]);
// n é do tipo 'número'
const n = firstElement ([ 1 , 2 , 3 ]);
// você é do tipo indefinido
const u = firstElement ([]);

Inferência

Observe que não precisamos especificar o Tipo neste exemplo. O tipo foi inferido - escolhido
automaticamente - por TypeScript.

Página 60
Podemos usar vários parâmetros de tipo também. Por exemplo, uma versão autônoma do mapa pareceria
assim:

mapa de funções < Input , Output > ( arr : Input [], func : ( arg : Input ) => Output ): O
return arr . map ( func );
}

// O parâmetro 'n' é do tipo 'string'


// 'analisado' é do tipo 'número []'
const parsed = map ([ "1" , "2" , "3" ], ( n ) => parseInt ( n ));

Observe que, neste exemplo, o TypeScript pode inferir tanto o tipo do parâmetro de tipo de entrada (de
a matriz de string fornecida ), bem como o parâmetro de tipo de saída com base no valor de retorno do
expressão da função ( número ).

Restrições

Escrevemos algumas funções genéricas que podem funcionar em qualquer tipo de valor. Às vezes nós queremos
relacionar dois valores, mas só pode operar em um determinado subconjunto de valores. Neste caso, podemos usar um
restrição para limitar os tipos de tipos que um parâmetro de tipo pode aceitar.

Vamos escrever uma função que retorna o maior de dois valores. Para fazer isso, precisamos de uma propriedade de comprimento
isso é um número. Restringimos o parâmetro de tipo a esse tipo escrevendo uma cláusula extends :

https://translate.googleusercontent.com/translate_f 46/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 61

function longest < Type extends { length : number }> ( a : Type , b : Type ) {
if ( a . comprimento > = b . comprimento ) {
return a ;
} else {
return b ;
}
}

// longArray é do tipo 'número []'


const longerArray = mais longo ([ 1 , 2 ], [ 1 , 2 , 3 ]);
// longString é do tipo 'alice' | 'prumo'
const longerString = mais longo ( "Alice" , "bob" );
// Erro! Os números não têm uma propriedade 'comprimento'
const notOK = mais longo ( 10 , 100 );

O
O argumento
argumento do
do tipo
tipo 'número'
'número' não
não éé atribuível
atribuível ao
ao parâmetro
parâmetro do
do tipo
tipo '{
'{
comprimento:
comprimento: número;
número; }} '.'.

Existem algumas coisas interessantes a serem observadas neste exemplo. Permitimos que o TypeScript inferisse o retorno
tipo de mais longo . A inferência de tipo de retorno também funciona em funções genéricas.

Como restringimos o tipo a {length: number} , fomos autorizados a acessar o .length


propriedade dos parâmetros a e b . Sem a restrição de tipo, não seríamos capazes de acessar
essas propriedades porque os valores podem ter sido de algum outro tipo sem uma propriedade de comprimento.

Os tipos de longArray e longString foram inferidos com base nos argumentos.


Lembre-se de que os genéricos tratam de relacionar dois ou mais valores com o mesmo tipo!

Por fim, como gostaríamos, a chamada para o mais longo (10, 100) é rejeitada porque o tipo de número
não tem uma propriedade .length .

Trabalhando com Valores Restritos

Este é um erro comum ao trabalhar com restrições genéricas:

https://translate.googleusercontent.com/translate_f 47/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Página 62

function minimumLength < Type extends { length : number }> (


obj : Tipo ,
mínimo : número
): Digite {
if ( obj . comprimento > = mínimo ) {
return obj ;
} else {
return { length: minimum };

Digite
Digite '{comprimento:
'{comprimento: número;
número; }} 'não
'não pode
pode ser
ser atribuído
atribuído ao
ao tipo'
tipo' Tipo
Tipo '.'.
'{comprimento:
'{comprimento: número;
número; }} 'é'é atribuível
atribuível àà restrição
restrição do
do tipo'
tipo' Tipo
Tipo ',',
mas
mas 'Tipo'
'Tipo' pode
pode ser
ser instanciado
instanciado com
com um
um subtipo
subtipo diferente
diferente de
de restrição
restrição '{
'{comprimento:
comprimento: número;
número;} }'. '.

}
}

Pode parecer que esta função está OK - o tipo é restrito a {comprimento: número} , e o
função retorna Type ou um valor correspondente a essa restrição. O problema é que a função
promete retornar o mesmo tipo de objeto que foi passado, não apenas algum objeto que corresponda ao
limitação. Se este código fosse legal, você poderia escrever um código que definitivamente não funcionaria:

// 'arr' obtém valor {comprimento: 6}


const arr = comprimento mínimo ([ 1 , 2 , 3 ], 6 );
// e trava aqui porque os arrays têm
// um método 'slice', mas não o objeto retornado!
console . log ( fatia arr . ( 0 ));

Especificando Argumentos de Tipo

TypeScript geralmente pode inferir os argumentos de tipo pretendidos em uma chamada genérica, mas nem sempre. Para
exemplo, digamos que você escreveu uma função para combinar duas matrizes:

function combine < Type > ( arr1 : Type [], arr2 : Type []): Type [] {
return arr1 . concat ( arr2 );
}

Normalmente, seria um erro chamar esta função com matrizes incompatíveis:

Página 63

const arr = combinar ([ 1 , 2 , 3 ], [ "olá" ]);

O
O tipo
tipo 'string'
'string' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo 'número'.
'número'.

Se você pretendia fazer isso, no entanto, poderia especificar manualmente o Tipo :

const arr = combinar < string | número > ([ 1 , 2 , 3 ], [ "olá" ]);

Diretrizes para escrever boas funções genéricas


https://translate.googleusercontent.com/translate_f 48/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Escrever funções genéricas é divertido e pode ser fácil se deixar levar pelos parâmetros de tipo.
Ter muitos parâmetros de tipo ou usar restrições onde eles não são necessários pode fazer
inferir chamadores menos bem-sucedidos, frustrantes de sua função.

Empurre os parâmetros de tipo para baixo

Aqui estão duas maneiras de escrever uma função que parecem semelhantes:

function firstElement1 < Type > ( arr : Type []) {


return arr [ 0 ];
}

function firstElement2 < Type extends any []> ( arr : Type ) {


return arr [ 0 ];
}

// a: número (bom)
const a = firstElement1 ([ 1 , 2 , 3 ]);
// b: qualquer (ruim)
const b = firstElement2 ([ 1 , 2 , 3 ]);

Eles podem parecer idênticos à primeira vista, mas firstElement1 é uma maneira muito melhor de escrever isso
função. Seu tipo de retorno inferido é Type , mas o tipo de retorno inferido de firstElement2 é qualquer
porque o TypeScript precisa resolver a expressão arr [0] usando o tipo de restrição, em vez de
"esperando" para resolver o elemento durante uma chamada.

Regra : quando possível, use o próprio parâmetro de tipo em vez de restringi-lo

Página 64

Use menos parâmetros de tipo

Aqui está outro par de funções semelhantes:

function filter1 < Type > ( arr : Type [], func : ( arg : Type ) => boolean ): Type []
return arr . filtro ( função );
}

function filter2 < Type , Func extends ( arg : Type ) => boolean > (
arr : Digite [],
func : Func
): Digite [] {
return arr . filtro ( função );
}

Criamos um parâmetro de tipo Func que não relaciona dois valores. Isso é sempre uma bandeira vermelha,
porque significa que os chamadores que desejam especificar argumentos de tipo têm que especificar manualmente um tipo extra
argumento sem motivo. Func não faz nada, mas torna a função mais difícil de ler e
razão sobre!

Regra : sempre use o mínimo possível de parâmetros de tipo

Os parâmetros de tipo devem aparecer duas vezes

https://translate.googleusercontent.com/translate_f 49/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Às vezes, esquecemos que uma função pode não precisar ser genérica:

function greet < Str extends string > ( s : Str ) {


console . log ( "Olá," + s );
}

saudar ( "mundo" );

Poderíamos facilmente ter escrito uma versão mais simples:

Página 65

função saudação ( s : string ) {


console . log ( "Olá," + s );
}

Lembre-se de que os parâmetros de tipo são para relacionar os tipos de valores múltiplos. Se um parâmetro de tipo for apenas
usado uma vez na assinatura da função, não está relacionando nada.

Regra : se um parâmetro de tipo aparecer apenas em um local, reconsidere fortemente se você realmente precisar dele

Parâmetros Opcionais
As funções em JavaScript geralmente aceitam um número variável de argumentos. Por exemplo, o toFixed
método de número leva uma contagem de dígitos opcional:

função f ( n : número ) {
console . log ( n . para corrigido ()); // 0 argumentos
console . log ( n . para corrigido ( 3 )); // 1 argumento
}

Podemos modelar isso no TypeScript marcando o parâmetro como opcional com ? :

função f ( x ?: número ) {
// ...
}
f (); // OK
f ( 10 ); // OK

Embora o parâmetro seja especificado como número do tipo , o parâmetro x terá, na verdade, o tipo

número | undefined porque parâmetros não especificados em JavaScript obtêm o valor undefined .

Você também pode fornecer um parâmetro padrão:

https://translate.googleusercontent.com/translate_f 50/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 66

função f ( x = 10 ) {
// ...
}

Agora, no corpo de f , x terá um número de tipo porque qualquer argumento indefinido será
substituído por 10 . Observe que quando um parâmetro é opcional, os chamadores sempre podem passar indefinido , como
isso simplesmente simula um argumento "ausente":

declara a função f ( x ?: número ): void ;


// cortar
// Tudo bem
f ();
f ( 10 );
f ( indefinido );

Parâmetros opcionais em retornos de chamada

Depois de aprender sobre parâmetros opcionais e expressões de tipo de função, é muito fácil
cometa os seguintes erros ao escrever funções que invocam retornos de chamada:

function myForEach ( arr : any [], callback : ( arg : any , index ?: number ) => voi
para ( deixar i = 0 ; i < arr . comprimento ; i ++) {
retorno de chamada ( arr [ i ], i );
}
}

O que as pessoas geralmente pretendem ao escrever o índice? como um parâmetro opcional é que eles querem ambos
dessas chamadas para ser legal:

myForEach ([ 1 , 2 , 3 ], ( a ) => console . log ( a ));


myForEach ([ 1 , 2 , 3 ], ( a , i ) => console . log ( a , i ));

O que isso realmente significa é que o retorno de chamada pode ser invocado com um argumento. Em outras palavras,
a definição da função diz que a implementação pode ser assim:

Página 67

function myForEach ( arr : any [], callback : ( arg : any , index ?: number ) => voi
para ( deixar i = 0 ; i < arr . comprimento ; i ++) {
// Não estou com vontade de fornecer o índice hoje
retorno de chamada ( arr [ i ]);
}
}

https://translate.googleusercontent.com/translate_f 51/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Por sua vez, o TypeScript reforçará esse significado e emitirá erros que não são realmente possíveis:

myForEach ([ 1 , 2 , 3 ], ( a , i ) => {
console . log ( i . toFixed ());

O
O objeto
objeto éé possivelmente
possivelmente 'indefinido'.
'indefinido'.

});

Em JavaScript, se você chamar uma função com mais argumentos do que parâmetros, o
os argumentos são simplesmente ignorados. O TypeScript se comporta da mesma maneira. Funções com menos parâmetros
(do mesmo tipo) pode sempre substituir funções com mais parâmetros.

Ao escrever um tipo de função para um retorno de chamada, nunca escreva um parâmetro opcional, a menos que pretenda chamar o
funcionar sem passar esse argumento

Sobrecargas de função
Algumas funções JavaScript podem ser chamadas em uma variedade de tipos e contagens de argumento. Por exemplo,
você pode escrever uma função para produzir uma data que leva um carimbo de data / hora (um argumento) ou um
especificação de mês / dia / ano (três argumentos).

No TypeScript, podemos especificar uma função que pode ser chamada de diferentes maneiras, escrevendo a sobrecarga
assinaturas. Para fazer isso, escreva algum número de assinaturas de função (geralmente duas ou mais), seguido por
o corpo da função:

Página 68

função makeDate ( timestamp : number ): Date ;


função makeDate ( m : número , d : número , y : número ): Data ;
function makeDate ( mOrTimestamp : número , d ?: número , y ?: número ): Data {
if ( d ! == undefined && y ! == undefined ) {
retornar nova data ( y , mOrTimestamp , d );
} else {
retornar nova data ( mOrTimestamp );
}
}
const d1 = makeDate ( 12345678 );
const d2 = makeDate ( 5 , 5 , 5 );
const d3 = makeDate ( 1 , 3 );

Nenhuma
Nenhuma sobrecarga
sobrecarga espera
espera 22 argumentos,
argumentos, mas
mas existem
existem sobrecargas
sobrecargas que
que esperam
esperam qualquer um
11 ou
ou 33 argumentos.
argumentos.

Neste exemplo, escrevemos duas sobrecargas: uma aceitando um argumento e outra aceitando três
argumentos. Essas duas primeiras assinaturas são chamadas de assinaturas de sobrecarga.

Em seguida, escrevemos uma implementação de função com uma assinatura compatível. Funções têm um
assinatura de implementação, mas essa assinatura não pode ser chamada diretamente. Mesmo que tenhamos escrito um
função com dois parâmetros opcionais após o obrigatório, não pode ser chamada com dois
https://translate.googleusercontent.com/translate_f 52/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

parâmetros!

Assinaturas de sobrecarga e a assinatura de implementação

Esta é uma fonte comum de confusão. Muitas vezes as pessoas escreverão um código como este e não entenderão
por que há um erro:

função fn ( x : string ): void ;


function fn () {
// ...
}
// Espera-se que seja capaz de chamar com nenhum argumento
fn ();

Esperava-se
Esperava-se 11 argumento,
argumento, mas
mas obteve
obteve 0.
0.

Novamente, a assinatura usada para escrever o corpo da função não pode ser "vista" de fora.

Página 69
A assinatura da implementação não é visível do exterior. Ao escrever uma função sobrecarregada,

você deve sempre ter duas ou mais assinaturas acima da implementação da função.

A assinatura de implementação também deve ser compatível com as assinaturas de sobrecarga. Por exemplo,
essas funções têm erros porque a assinatura de implementação não corresponde às sobrecargas em um
Maneira correta:

função fn ( x : booleano ): void ;


// O tipo de argumento não está certo
função fn ( x : string ): void ;

Esta
Esta assinatura
assinatura de
de sobrecarga
sobrecarga não
não éé compatível
compatível com
com sua
sua implementação
implementação
assinatura.
assinatura.

função fn ( x : boolean ) {}

função fn ( x : string ): string ;


// O tipo de retorno não está certo
função fn ( x : número ): booleano ;

Esta
Esta assinatura
assinatura de
de sobrecarga
sobrecarga não
não éé compatível
compatível com
com sua
sua implementação
implementação
assinatura.
assinatura.

função fn ( x : string | número ) {


retornar "oops" ;
}

Escrevendo Boas Sobrecargas

Como os genéricos, existem algumas diretrizes que você deve seguir ao usar sobrecargas de função.
Seguir esses princípios tornará sua função mais fácil de chamar, mais fácil de entender e mais fácil de
implemento.

Vamos considerar uma função que retorna o comprimento de uma string ou matriz:

https://translate.googleusercontent.com/translate_f 53/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
função len ( s : string ): número ;
função len ( arr : any []): number ;
função len ( x : qualquer ) {
return x . comprimento ;
}

Página 70
Esta função está bem; podemos invocá-lo com strings ou arrays. No entanto, não podemos invocá-lo com um valor
pode ser uma string ou uma matriz, porque o TypeScript só pode resolver uma chamada de função para um único
sobrecarga:

len ( "" ); // OK
len ([ 0 ]); // OK
len ( Math . random ()> 0,5 ? "olá" : [ 0 ]);

Nenhuma
Nenhuma sobrecarga
sobrecarga corresponde
corresponde aa esta
esta chamada.
chamada.
Sobrecarga
Sobrecarga 11 de
de 2,
2, '(s:
'(s: string):
string): número',
número', gerou
gerou oo seguinte
seguinte erro.
erro.
Argumento
Argumento do
do tipo
tipo 'número
'número []
[] || "olá"
"hello"
'não
'não
é atribuível
é atribuível
a ao parâmetro
parâmetro
do tipo 'string'.
do tipo 'string'.
O
O tipo
tipo 'número
'número []'
[]' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo 'string'.
'string'.
Sobrecarga
Sobrecarga 22 de
de 2,
2, '(arr:
'(arr: any
any []):
[]): number',
number', gerou
gerou oo seguinte
seguinte erro.
erro.
Argumento
Argumento do
do tipo
tipo 'número
'número []
[] || "olá"
"hello"
'não
'não
é atribuível
é atribuível
a ao parâmetro
parâmetro
do tipo 'qualquer
do tipo[]'.
'any []'.
O
O tipo
tipo 'string'
'string' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo 'any
'any []'.
[]'.

Como ambas as sobrecargas têm a mesma contagem de argumentos e o mesmo tipo de retorno, podemos, em vez disso, escrever
uma versão não sobrecarregada da função:

função len ( x : qualquer [] | string ) {


return x . comprimento ;
}

Isto é muito melhor! Os chamadores podem invocar isso com qualquer tipo de valor e, como um bônus adicional, nós
não precisa descobrir uma assinatura de implementação correta.

Sempre prefira parâmetros com tipos de união em vez de sobrecargas, quando possível

Declarando isso em uma função

O TypeScript inferirá o que isso deve ser em uma função por meio da análise de fluxo de código, por exemplo, em
a seguir:

Página 71

const user = {
id: 123 ,

https://translate.googleusercontent.com/translate_f 54/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
admin: falso ,
se torneAdmin : function () {
isso . admin = verdadeiro ;
},
};

TypeScript entende que a função user.becomeAdmin tem um correspondente this que é


o usuário do objeto externo . isso , heh, pode ser suficiente para muitos casos, mas existem muitos casos
onde você precisa de mais controle sobre o objeto que isso representa. A especificação do JavaScript afirma
que você não pode ter um parâmetro chamado this , e então o TypeScript usa esse espaço de sintaxe para permitir que você
declare o tipo para this no corpo da função.

interface DB {
filterUsers ( filtro : ( este : Usuário ) => booleano ): Usuário [];
}

const db = getDB ();


const admins = db . filterUsers ( function ( this : User ) {
devolva isso . admin ;
});

Este padrão é comum com APIs de estilo de retorno de chamada, onde outro objeto normalmente controla quando seu
função é chamada. Observe que você precisa usar funções e não funções de seta para obter este
comportamento:

interface DB {
filterUsers ( filtro : ( este : Usuário ) => booleano ): Usuário [];
}

const db = getDB ();


const admins = db . filterUsers (() => this . admin );

A
A função
função de
de seta
seta contendo
contendo captura
captura oo valor
valor global
global de
de 'this'.
'this'.
O
O elemento
elemento tem
tem implicitamente
implicitamente um
um tipo
tipo 'qualquer'
'qualquer' porque
porque oo tipo
tipo 'typeof
'typeof globalThis'
globalThis' tem
não
semtem
assinatura
assinatura
de índice.
de índice.

Página 72

Outros tipos de conhecimento


Existem alguns tipos adicionais que você deseja reconhecer que aparecem frequentemente ao trabalhar com
tipos de função. Como todos os tipos, você pode usá-los em qualquer lugar, mas são especialmente relevantes no
contexto de funções.

vazio

void representa o valor de retorno de funções que não retornam um valor. É o tipo inferido qualquer
vez que uma função não tem nenhuma instrução de retorno , ou não retorna nenhum valor explícito de
essas declarações de retorno:

// O tipo de retorno inferido é nulo


function noop () {
retorno ;
}

https://translate.googleusercontent.com/translate_f 55/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Em JavaScript, uma função que não retorna nenhum valor retornará implicitamente o valor indefinido .
No entanto, void e undefined não são a mesma coisa no TypeScript. Existem mais detalhes em
no final deste capítulo.

void não é o mesmo que undefined .

objeto

O objeto de tipo especial se refere a qualquer valor que não seja primitivo ( string , número , bigint ,

booleano , símbolo , nulo ou indefinido ). Isso é diferente do tipo de objeto vazio {} , e


também diferente do tipo global Object . É muito provável que você nunca use Object .

objeto não é objeto . Sempre use objeto !

Observe que em JavaScript, os valores de função são objetos: eles têm propriedades, têm
Object.prototype em sua cadeia de protótipo, são instanceof Object , você pode chamar
Object.keys neles e assim por diante. Por este motivo, os tipos de função são considerados objetos s em
TypeScript.

Página 73
desconhecido

O tipo desconhecido representa qualquer valor. É semelhante a qualquer tipo, mas é mais seguro porque é
não é legal fazer nada com um valor desconhecido :

função f1 ( a : qualquer ) {
a . b (); // OK
}
função f2 ( a : desconhecido ) {
a . b ();

O
O objeto
objeto éé do
do tipo
tipo 'desconhecido'.
'desconhecido'.

Isso é útil ao descrever tipos de função porque você pode descrever funções que aceitam qualquer
valor sem ter nenhum valor no corpo da função.

Por outro lado, você pode descrever uma função que retorna um valor de tipo desconhecido:

function safeParse ( s : string ): desconhecido {


return JSON . analisar ( s );
}

// Precisa ter cuidado com 'obj'!


const obj = safeParse ( someRandomString );

nunca

Algumas funções nunca retornam um valor:

https://translate.googleusercontent.com/translate_f 56/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

falha de função ( msg : string ): nunca {


lançar novo erro ( msg );
}

O tipo never representa valores que nunca são observados. Em um tipo de retorno, isso significa que o
função lança uma exceção ou termina a execução do programa.

Página 74
nunca também aparece quando o TypeScript determina que não há mais nada em uma união.

função fn ( x : string | número ) {


if ( typeof x === "string" ) {
// faça alguma coisa
} else if ( typeof x === "número" ) {
// faça outra coisa
} else {
x ; // tem tipo 'nunca'!
}
}

Função

O tipo global Function descreve propriedades como bind , call , apply e outras presentes em
todos os valores de função em JavaScript. Ele também tem a propriedade especial de que os valores do tipo Function podem
sempre ser chamado; essas chamadas retornam qualquer :

function doSomething ( f : Function ) {


retornar f ( 1 , 2 , 3 );
}

Esta é uma chamada de função sem tipo e geralmente é melhor evitada por causa da falta de segurança de qualquer retorno
modelo.

Se você precisa aceitar uma função arbitrária, mas não pretende chamá-la, o type () => void é
geralmente mais seguro.

Parâmetros e argumentos de descanso

Leitura de fundo:
Parâmetros de repouso
Parâmetros de repouso

Além de usar parâmetros opcionais ou sobrecargas para fazer Spread Syntax

funções que podem aceitar uma variedade de contagens de argumentos fixos, podemos
também define funções que usam um número ilimitado de argumentos usando parâmetros de descanso.

Um parâmetro rest aparece após todos os outros parâmetros e usa a sintaxe ... :

https://translate.googleusercontent.com/translate_f 57/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Página 75

função multiply ( n : número , ... m : número []) {


return m . map (( x ) => n * x );
}
// 'a' obtém valor [10, 20, 30, 40]
const a = multiplicação ( 10 , 1 , 2 , 3 , 4 );

No TypeScript, a anotação de tipo nesses parâmetros é implicitamente any [] em vez de any , e any
a anotação de tipo fornecida deve ser da forma Array <T> ou T [] , ou um tipo de tupla (que aprenderemos
sobre mais tarde).

Argumentos de Resto

Por outro lado, podemos fornecer um número variável de argumentos de uma matriz usando a sintaxe de propagação.
Por exemplo, o método push de matrizes aceita qualquer número de argumentos:

const arr1 = [ 1 , 2 , 3 ];
const arr2 = [ 4 , 5 , 6 ];
arr1 . push (... arr2 );

Observe que, em geral, o TypeScript não pressupõe que as matrizes sejam imutáveis. Isso pode levar a alguns
comportamento surpreendente:

// O tipo inferido é o número [] - "uma matriz com zero ou mais números",


// não especificamente dois números
const args = [ 8 , 5 ];
ângulo const = matemática . atan2 (... args );

Um
Um argumento
argumento de
de propagação
propagação deve
deve ter
ter um
um tipo
tipo de
de tupla
tupla ou
ou ser
ser passado
passado para
para um
um resto
resto
parâmetro.
parâmetro.

A melhor solução para esta situação depende um pouco do seu código, mas, em geral, um contexto const é o
solução mais simples:

Página 76

// Inferido como tupla de 2 comprimentos


const args = [ 8 , 5 ] como const ;
// OK
ângulo const = matemática . atan2 (... args );

O uso de argumentos restantes pode exigir a ativação downlevelIteration ao segmentar mais velhos
tempos de execução.

Destruição de Parâmetros
Você pode usar a desestruturação de parâmetros para descompactar convenientemente

https://translate.googleusercontent.com/translate_f 58/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
objetos fornecidos como um argumento em uma ou mais variáveis ​locais em Leitura de fundo:
Atribuição de Destruição
o corpo de função. Em JavaScript, é assim:

soma da função ({ a , b , c }) {
console . log ( a + b + c );
}
soma ({ a: 10 , b: 3 , c: 9 });

A anotação de tipo para o objeto segue a sintaxe de desestruturação:

soma da função ({ a , b , c }: { a : número ; b : número ; c : número }) {


console . log ( a + b + c );
}

Isso pode parecer um pouco prolixo, mas você também pode usar um tipo nomeado aqui:

// Igual ao exemplo anterior


tipo ABC = { a : número ; b : número ; c : número };
soma da função ({ a , b , c }: ABC ) {
console . log ( a + b + c );
}

Atribuições de funções

Página 77
Tipo de retorno vazio

O tipo de retorno void para funções pode produzir algum comportamento incomum, mas esperado.

Digitação Contextual com um tipo de retorno de vazio se não forçar funções para não retornar algo.
Outra maneira de dizer isso é um tipo de função contextual com um tipo de retorno nulo ( tipo vf = () =>

void ), quando implementado, pode retornar qualquer outro valor, mas será ignorado.

Assim, as seguintes implementações do tipo () => void são válidas:

digite voidFunc = () => void ;

const f1 : voidFunc = () => {


return true ;
};

const f2 : voidFunc = () => verdadeiro ;

const f3 : voidFunc = function () {


return true ;
};

E quando o valor de retorno de uma dessas funções é atribuído a outra variável, ele manterá o
tipo de vazio :

const v1 = f1 ();

https://translate.googleusercontent.com/translate_f 59/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

const v2 = f2 ();

const v3 = f3 ();

Esse comportamento existe para que o código a seguir seja válido mesmo que Array.prototype.push
retorna um número e o método Array.prototype.forEach espera uma função com um retorno
tipo de vazio .

Página 78

const src = [ 1 , 2 , 3 ];
const dst = [ 0 ];

src . forEach (( el ) => dst . push ( el ));

Há um outro caso especial a ter em conta, quando uma definição de função literal tem um retorno nulo
tipo, essa função não deve retornar nada.

função f2 (): void {


// @ ts-expect-error
return true ;
}

const f3 = function (): void {


// @ ts-expect-error
return true ;
};

Para obter mais informações sobre void , consulte estas outras entradas de documentação:

manual v1

manual v2

FAQ - "Por que as funções retornando não-nulo podem ser atribuídas à função retornando nulo?"

https://translate.googleusercontent.com/translate_f 60/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 79

Tipos de Objetos

Em JavaScript, a forma fundamental com que agrupamos e transmitimos dados é por meio de objetos. No
TypeScript, nós os representamos por meio de tipos de objetos.

Como vimos, eles podem ser anônimos:

função saudação ( pessoa : { nome : string ; idade : número }) {


retornar "Olá" + pessoa . nome ;
}

ou eles podem ser nomeados usando uma interface

interface Person {
nome : string ;
idade : número ;
}

cumprimenta função ( pessoa : Pessoa ) {


retornar "Olá" + pessoa . nome ;
}

ou um alias de tipo.

tipo Person = {
nome : string ;
idade : número ;
};

cumprimenta função ( pessoa : Pessoa ) {


retornar "Olá" + pessoa . nome ;
}

Em todos os três exemplos acima, escrevemos funções que pegam objetos que contêm a propriedade
nome (que deve ser uma string ) e idade (que deve ser um número ).

Página 80

Modificadores de propriedade
Cada propriedade em um tipo de objeto pode especificar algumas coisas: o tipo, se a propriedade é
opcional e se a propriedade pode ser gravada.

Propriedades Opcionais

Na maior parte do tempo, estaremos lidando com objetos que podem ter um conjunto de propriedades. Naqueles
casos, podemos marcar essas propriedades como opcionais, adicionando um ponto de interrogação ( ? ) ao final de seus
https://translate.googleusercontent.com/translate_f 61/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

nomes.

interface PaintOptions {
forma : forma ;
xPos ?: número ;
yPos ?: número ;
}

function paintShape ( opts : PaintOptions ) {


// ...
}

forma const = getShape ();


paintShape ({ forma });
paintShape ({ forma , xPos: 100 });
paintShape ({ shape , yPos: 100 });
paintShape ({ shape , xPos: 100 , yPos: 100 });

Neste exemplo, xPos e yPos são considerados opcionais. Podemos escolher fornecer qualquer um dos
eles, então todas as chamadas acima para paintShape são válidas. Tudo o que a opcionalidade realmente diz é que se a propriedade é
definido, é melhor ter um tipo específico.

Também podemos ler essas propriedades - mas quando fazemos sob strictNullChecks, TypeScript
vai nos dizer que eles são potencialmente indefinidos .

Página 81

function paintShape ( opts : PaintOptions ) {


deixe xPos = opts . xPos ;

(propriedade) PaintOptions.xPos ?: número | Indefinido

deixe yPos = opts . yPos ;

(propriedade) PaintOptions.yPos ?: número | Indefinido

// ...
}

Em JavaScript, mesmo que a propriedade nunca tenha sido definida, ainda podemos acessá-la - ela apenas nos dará
o valor indefinido . Podemos apenas lidar com undefined especialmente.

function paintShape ( opts : PaintOptions ) {


deixe xPos = opts . xPos === indefinido ? 0 : opta . xPos ;

deixe xPos: número

deixe yPos = opts . yPos === undefined ? 0 : opta . yPos ;

https://translate.googleusercontent.com/translate_f 62/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
deixe yPos: número

// ...
}

Observe que esse padrão de configuração de padrões para valores não especificados é tão comum que o JavaScript tem
sintaxe para apoiá-lo.

Página 82

function paintShape ({ shape , xPos = 0 , yPos = 0 }: PaintOptions ) {


console . log ( "coordenada x em" , xPos );

(parâmetro) xPos: número

console . log ( "coordenada y em" , yPos );

(parâmetro) yPos: número

// ...
}

Aqui usamos um padrão de desestruturação parao parâmetro paintShape , e fornecidovalores padrão para

xPos e yPos . Agora, xPos e yPos estão definitivamente presentes dentro do corpo de
paintShape , mas opcional para qualquer chamador para paintShape .

Observe que atualmente não há como colocar anotações de tipo nos padrões de desestruturação. Isto é porque

a sintaxe a seguir já significa algo diferente em JavaScript.

function draw ({ shape : Shape , xPos : number = 100 /*...*/ }) {


render ( forma );

Não
Não éé possível
possível encontrar
encontrar oo nome
nome 'forma'.
'forma'. Você
Você quis
quis dizer
dizer 'Forma'?
'Forma'?

render ( xPos );

Não
Não éé possível
possível encontrar
encontrar oo nome
nome 'xPos'.
'xPos'.

Em um padrão de desestruturação de objeto, forma: Forma significa "pegue a forma da propriedade e redefina
-lo localmente como uma variável chamada Forma . Da mesma forma, xPos: número cria uma variável chamada número
cujo valor é baseado no xPos do parâmetro .

Usando modificadores de mapeamento , você pode remover atributos opcionais .

https://translate.googleusercontent.com/translate_f 63/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Propriedades somente leitura

Página 83
As propriedades também podem ser marcadas como somente leitura para TypeScript. Embora não mude nenhum comportamento em
tempo de execução, uma propriedade marcada como somente leitura não pode ser gravada durante a verificação de tipo.

interface SomeType {
readonly prop : corda ;
}

function doSomething ( obj : SomeType ) {


// Podemos ler em 'obj.prop'.
console . log ( `prop tem o valor ' $ { obj . prop } ' .` );

// Mas não podemos reatribuí-lo.


obj . prop = "olá" ;

Não
Não éé possível
possível atribuir
atribuir aa 'prop'
'prop' porque
porque éé uma
uma propriedade
propriedade somente
somente leitura.
leitura.

Usar o modificador somente leitura não implica necessariamente que um valor seja totalmente imutável - ou em
outras palavras, que seu conteúdo interno não pode ser alterado. Significa apenas que a propriedade em si não pode ser recuperada
escrito para.

interface Home {
residente somente leitura : { nome : string ; idade : número };
}

function visitForBirthday ( home : Home ) {


// Podemos ler e atualizar propriedades de 'home.resident'.
console . log ( `Feliz aniversário $ { casa . residente . nome } !` );
casa . residente . idade ++;
}

despejo de função ( casa : casa ) {


// Mas não podemos escrever para a própria propriedade 'residente' em uma 'Casa'.
casa . residente = {

Não
Não éé possível
possível atribuir
atribuir aa 'residente'
'residente' porque
porque éé uma
uma propriedade
propriedade somente
somente leitura.
leitura.

nome: "Victor the Evictor" ,


idade: 42 ,
};
}

Página 84
É importante gerenciar as expectativas do que implica somente leitura . É útil sinalizar a intenção durante
tempo de desenvolvimento para TypeScript sobre como um objeto deve ser usado. TypeScript não leva em consideração
se as propriedades em dois tipos são somente leitura ao verificar se esses tipos são
compatível, portanto, as propriedades somente leitura também podem ser alteradas por meio de aliasing.

https://translate.googleusercontent.com/translate_f 64/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

interface Person {
nome : string ;
idade : número ;
}

interface ReadonlyPerson {
nome somente leitura : string ;
idade somente leitura : número ;
}

let writablePerson : Person = {


nome: "Person McPersonface" ,
idade: 42 ,
};

// trabalho
deixe readonlyPerson : ReadonlyPerson = writablePerson ;

console . log (pessoa somente leitura . idade ); // imprime '42'


writablePerson . idade ++;
console . log (pessoa somente leitura . idade ); // imprime '43'

Usando modificadores de mapeamento , você pode remover atributos somente leitura .

Assinaturas de índice

Às vezes, você não sabe todos os nomes das propriedades de um tipo com antecedência, mas conhece o
forma dos valores.

Nesses casos, você pode usar uma assinatura de índice para descrever os tipos de valores possíveis, por exemplo:

Página 85

interface StringArray {
[ índice : número ]: string ;
}

const meuArray : StringArray = getStringArray ();


const secondItem = myArray [ 1 ];

const secondItem: string

Acima, temos uma interface StringArray que possui uma assinatura de índice. Esta assinatura de índice indica
que quando um StringArray é indexado com um número , ele retornará uma string .

Um tipo de propriedade de assinatura de índice deve ser 'string' ou 'número'.

É possível suportar os dois tipos de indexadores ...

Embora as assinaturas de índice de string sejam uma maneira poderosa de descrever o padrão de "dicionário", elas também

https://translate.googleusercontent.com/translate_f 65/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
fazer com que todas as propriedades correspondam ao seu tipo de retorno. Isso ocorre porque um índice de string declara que
obj.property também está disponível como obj ["propriedade"] . No exemplo a seguir, o tipo de nome
não corresponde ao tipo do índice da string e o verificador de tipo fornece um erro:

interface NumberDictionary {
[ índice : string ]: número ;

comprimento : número ; // OK
nome : string ;

A
A propriedade
propriedade 'nome'
'nome' do
do tipo
tipo 'string'
'string' não
não pode
pode ser
ser atribuída
atribuída ao
ao índice
tipo de'string'
índice 'string'
digite
'número'.
'número'.

No entanto, propriedades de diferentes tipos são aceitáveis ​se a assinatura do índice for uma união do
tipos de propriedade:

Página 86

interface NumberOrStringDictionary {
[ índice : string ]: número | string ;
comprimento : número ; // ok, o comprimento é um número
nome : string ; // ok, o nome é uma string
}

Finalmente, você pode tornar as assinaturas de índice somente leitura para evitar a atribuição a seus índices:

interface ReadonlyStringArray {
somente leitura [ índice : número ]: string ;
}

deixar meuArray : ReadonlyStringArray = getReadOnlyStringArray ();


meuArray [ 2 ] = "Mallory" ;

A
A assinatura
assinatura de
de índice
índice no
no tipo
tipo 'ReadonlyStringArray'
'ReadonlyStringArray' permite
permite apenas
apenas aa leitura.
leitura.

Você não pode definir myArray [2] porque a assinatura do índice é somente leitura .

Tipos de extensão
É muito comum ter tipos que podem ser versões mais específicas de outros tipos. Por exemplo,
podemos ter um tipo BasicAddress que descreve os campos necessários para o envio de cartas e
pacotes nos EUA

interface BasicAddress {
nome ?: string ;
rua : string ;

https://translate.googleusercontent.com/translate_f 66/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
cidade : string ;
país : string ;
postalCode : string ;
}

Em algumas situações, isso é suficiente, mas os endereços costumam ter um número de unidade associado a eles se
o prédio em um endereço tem várias unidades. Podemos então descrever um AddressWithUnit .

Página 87

interface AddressWithUnit {
nome ?: string ;
unidade : string ;
rua : string ;
cidade : string ;
país : string ;
postalCode : string ;
}

Isso funciona, mas a desvantagem aqui é que tivemos que repetir todos os outros campos de
BasicAddress quando nossas alterações foram puramente aditivas. Em vez disso, podemos estender o original
Digite BasicAddress e apenas adicione os novos campos que são exclusivos para AddressWithUnit .

interface BasicAddress {
nome ?: string ;
rua : string ;
cidade : string ;
país : string ;
postalCode : string ;
}

interface AddressWithUnit extends BasicAddress {


unidade : string ;
}

A palavra-chave extends em uma interface nos permite copiar membros de outros


tipos nomeados e adicione quaisquer novos membros que desejar. Isso pode ser útil para reduzir o
quantidade de boilerplate de declaração de tipo que temos que escrever, e para sinalizar a intenção de que vários
diferentes declarações da mesma propriedade podem estar relacionadas. Por exemplo, AddressWithUnit
não precisava repetir a propriedade da rua e, como a rua se origina em BasicAddress ,
o leitor saberá que esses dois tipos estão relacionados de alguma forma.

as interfaces também podem se estender a vários tipos.

Página 88

https://translate.googleusercontent.com/translate_f 67/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

interface Colorful {
cor : string ;
}

interface Circle {
raio : número ;
}

interface ColourfulCircle extends Colourful , Circle {}

const cc : ColorfulCircle = {
cor: "vermelho" ,
raio: 42 ,
};

Tipos de interseção
interface s nos permitiu construir novos tipos a partir de outros tipos, estendendo-os. TypeScript
fornece outra construção chamada tipos de interseção que é usada principalmente para combinar objetos existentes
tipos.

Um tipo de interseção é definido usando o operador & .

interface Colorful {
cor : string ;
}
interface Circle {
raio : número ;
}

digite ColorfulCircle = Colorful & Circle ;

Aqui, cruzamos Colorido e Círculo para produzir um novo tipo que tem todos os membros de

Colorido e Círculo .

Página 89

desenho de função ( círculo : colorido e círculo ) {


console . log ( `A cor era $ { circle . color } ` );
console . log ( `O raio era $ { círculo . raio } ` );
}

// Certo
desenhar ({ cor: "azul" , raio: 42 });

// oops
desenhar ({ cor: "vermelho" , raidus: 42 });

Argumento
Argumento do
do tipo
tipo '{color:
'{color: string;
string; raidus:
raidus: número;
número; }} 'não
'não éé atribuível
atribuível a
para
parâmetro
o parâmetro
do tipodo
'Colorido
tipo 'Colorido
e Círculo'.
e Círculo'.
O
O literal
literal de
de objeto
objeto só
só pode
pode especificar
especificar propriedades
propriedades conhecidas,
conhecidas, mas
mas 'raidus'
'raidus' faz
não

https://translate.googleusercontent.com/translate_f 68/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
não
existem
existe
nono
tipo
tipo
'Colorido
'Colorido
e Círculo'.
e Círculo'.
Você
Você
quis
quis
dizer
dizer
'radius'?
'radius'?

Interfaces vs. Intersecções


Acabamos de ver duas maneiras de combinar tipos que são semelhantes, mas na verdade são sutilmente diferentes.
Com interfaces, poderíamos usar uma cláusula extends para estender de outros tipos, e fomos capazes de
faça algo semelhante com interseções e nomeie o resultado com um apelido de tipo. O princípio
diferença entre os dois é como os conflitos são tratados, e essa diferença é normalmente um dos
principais razões pelas quais você escolheria um em vez do outro entre uma interface e um alias de tipo de um
tipo de interseção.

Tipos de Objetos Genéricos


Vamos imaginar um tipo de caixa que pode conter qualquer valor - string s, número s, girafa s, seja o que for.

interface Box {
conteúdo : qualquer ;
}

No momento, a propriedade contents é digitada como qualquer , o que funciona, mas pode levar a acidentes para baixo
a linha.

Em vez disso, poderíamos usar desconhecido , mas isso significaria que, nos casos em que já conhecemos o tipo
de conteúdo , precisaríamos fazer verificações preventivas ou usar afirmações de tipo sujeitas a erros.

Página 90

interface Box {
conteúdo : desconhecido ;
}

deixe x : Box = {
conteúdo: "olá, mundo" ,
};

// podemos verificar 'x.contents'


if ( typeof x . contents === "string" ) {
console . log ( x . conteúdo . toLowerCase ());
}

// ou podemos usar uma declaração de tipo


console . log (( x . conteúdo como string ). toLowerCase ());

Uma abordagem de tipo seguro seria, em vez disso, construir diferentes tipos de caixa para cada tipo de

conteúdo .

interface NumberBox {
conteúdo : número ;
}

interface StringBox {
conteúdo : string ;
}

https://translate.googleusercontent.com/translate_f 69/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
interface BooleanBox {
conteúdo : booleano ;
}

Mas isso significa que teremos que criar funções diferentes, ou sobrecargas de funções, para operar
esses tipos.

Página 91

function setContents ( box : StringBox , newContents : string ): void ;


função setContents ( box : NumberBox , newContents : number ): void ;
função setContents ( box : BooleanBox , newContents : boolean ): void ;
function setContents ( box : { contents : any }, newContents : any ) {
caixa . conteúdo = newContents ;
}

Isso é muito clichê. Além disso, mais tarde, podemos precisar introduzir novos tipos e sobrecargas. Esse
é frustrante, uma vez que nossos tipos de caixa e sobrecargas são todos efetivamente os mesmos.

Em vez disso, podemos fazer um tipo Box genérico que declara um parâmetro de tipo.

caixa de interface < Tipo > {


conteúdo : Tipo ;
}

Você pode ler isso como “Uma caixa de tipo é algo cujo conteúdo tem o tipo Tipo” .
Mais tarde, quando nos referirmos a Box , temos que fornecer um argumento de tipo no lugar de Type .

let box : Box < string >;

Pense no Box como um modelo para um tipo real, onde Type é um marcador que será substituído por
algum outro tipo. Quando o TypeScript vir Box <string> , ele substituirá todas as instâncias de Type em

Box <Type> com string , e acaba funcionando com algo como {contents: string} . No
outras palavras, Box <string> e nossa StringBox anterior funcionam de forma idêntica.

https://translate.googleusercontent.com/translate_f 70/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 92

caixa de interface < Tipo > {


conteúdo : Tipo ;
}
interface StringBox {
conteúdo : string ;
}

let boxA : Box < string > = { contents: "hello" };


boxA . conteúdo ;

(propriedade) Caixa <string> .contents: string

let boxB : StringBox = { contents: "world" };


boxB . conteúdo ;

(propriedade) StringBox.contents: string

A caixa é reutilizável nesse tipo e pode ser substituída por qualquer coisa. Isso significa que quando precisamos de um
caixa para um novo tipo, não precisamos declarar um novo tipo de caixa (embora certamente poderíamos se nós
queria).

caixa de interface < Tipo > {


conteúdo : Tipo ;
}

interface Apple {
// ....
}

// O mesmo que '{contents: Apple}'.


digite AppleBox = Box < Apple >;

Isso também significa que podemos evitar sobrecargas inteiramente, em vez de usar funções genéricas .

function setContents < Type > ( box : Box < Type >, newContents : Type ) {
caixa . conteúdo = newContents ;
}

Página 93
É importante notar que os apelidos de tipo também podem ser genéricos. Poderíamos ter definido nosso novo Box <Type>
interface, que era:

caixa de interface < Tipo > {


conteúdo : Tipo ;
}

usando um alias de tipo em vez disso:

https://translate.googleusercontent.com/translate_f 71/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

tipo Caixa < Tipo > = {


conteúdo : Tipo ;
};

Uma vez que aliases de tipo, ao contrário de interfaces, podem descrever mais do que apenas tipos de objetos, também podemos usá-los
para escrever outros tipos de tipos auxiliares genéricos.

tipo OrNull < Type > = Type | null ;

tipo OneOrMany < Type > = Type | Digite [];

digite OneOrManyOrNull < Type > = OrNull < OneOrMany < Type >>;

tipo OneOrManyOrNull <Type> = OneOrMany <Type> | nulo

digite OneOrManyOrNullStrings = OneOrManyOrNull < string >;

tipo OneOrManyOrNullStrings = OneOrMany <string> | nulo

Vamos circular de volta para digitar aliases daqui a pouco.

O tipo de matriz

Os tipos de objetos genéricos costumam ser algum tipo de contêiner que funcionam independentemente do tipo de
elementos que eles contêm. É ideal que as estruturas de dados funcionem dessa maneira, para que sejam reutilizáveis ​em
diferentes tipos de dados.

Página 94
Acontece que temos trabalhado com um tipo exatamente como este ao longo deste manual: o Array
modelo. Sempre que escrevemos tipos como número [] ou string [] , isso é apenas uma abreviação para

Array <número> e Array <string> .

function doSomething ( value : Array < string >) {


// ...
}

deixe meuArray : string [] = [ "olá" , "mundo" ];

// qualquer um desses funciona!


doSomething ( meuArray );
doSomething ( new Array ( "hello" , "world" ));

Muito parecido com o tipo Box acima, o próprio Array é um tipo genérico.

interface Array < Type > {


/ **
* Obtém ou define o comprimento da matriz.
*/
comprimento : número ;

https://translate.googleusercontent.com/translate_f 72/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
/ **
* Remove o último elemento de uma matriz e o retorna.
*/
pop (): Tipo | indefinido ;

/ **
* Acrescenta novos elementos a uma matriz e retorna o novo comprimento de a
*/
push (... itens : Tipo []): número ;

// ...
}

JavaScript moderno também fornece outras estruturas de dados que são genéricas, como Map <K, V> ,

Defina <T> e Prometa <T> . Tudo isso realmente significa que por causa de como Map , Set e Promise
se comportar, eles podem trabalhar com qualquer conjunto de tipos.

Página 95
O tipo ReadonlyArray

O ReadonlyArray é um tipo especial que descreve matrizes que não devem ser alteradas.

function doStuff ( valores : ReadonlyArray < string >) {


// Podemos ler 'valores' ...
cópia const = valores . fatia ();
console . log ( `O primeiro valor é $ { values [ 0 ] } ` );

// ... mas não podemos alterar 'valores'.


valores . push ( "olá!" );

A
A propriedade
propriedade 'push'
'push' não
não existe
existe no
no tipo
tipo 'readonly
'readonly string
string []'.
[]'.

Muito parecido com o modificador somente leitura para propriedades, é principalmente uma ferramenta que podemos usar para fins. Quando nós
ver uma função que retorna ReadonlyArray s, ela nos diz que não devemos alterar o conteúdo em
todos, e quando vemos uma função que consome ReadonlyArray s, ela nos diz que podemos passar qualquer
array nessa função sem se preocupar com a alteração de seu conteúdo.

Ao contrário de Array , não há um construtor ReadonlyArray que possamos usar.

novo ReadonlyArray ( "vermelho" , "verde" , "azul" );

'ReadonlyArray'
'ReadonlyArray' se
se refere
refere apenas
apenas aa um
um tipo,
tipo, mas
mas está
está sendo
sendo usado
usado como
como um
um valor
valor aqui.
aqui.

Em vez disso, podemos atribuir Array s regulares a ReadonlyArray s.

const roArray : ReadonlyArray < seqüência > = [ "vermelho" , "verde" , "azul" ];

Assim como o TypeScript fornece uma sintaxe abreviada para Array <Type> com Type [] , ele também fornece um
sintaxe abreviada para ReadonlyArray <Type> com Readonly Type [] .
https://translate.googleusercontent.com/translate_f 73/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 96

function doStuff ( valores : string somente leitura []) {


// Podemos ler 'valores' ...
cópia const = valores . fatia ();
console . log ( `O primeiro valor é $ { values [ 0 ] } ` );

// ... mas não podemos alterar 'valores'.


valores . push ( "olá!" );

A
A propriedade
propriedade 'push'
'push' não
não existe
existe no
no tipo
tipo 'readonly
'readonly string
string []'.
[]'.

Uma última coisa a notar é que, ao contrário do modificador de propriedade somente leitura , a capacidade de atribuição não é
bidirecional entre regulares Matriz s e ReadonlyArray s.

deixe x : string somente leitura [] = [];


deixe y : string [] = [];

x=y;
y=x;

O
O tipo
tipo 'string
'string somente
somente leitura
leitura []'
[]' éé 'somente
'somente leitura'
leitura' ee não
não pode
pode ser
ser atribuído
atribuído aao
otipo
tipomutável
mutável'string
'string[]'.[]'.

Tipos de tupla

Um tipo de tupla é outro tipo de tipo Array que sabe exatamente quantos elementos ele contém, e
exatamente quais tipos ele contém em posições específicas.

digite StringNumberPair = [ string , número ];

Aqui, StringNumberPair é um tipo de tupla de string e número . Como ReadonlyArray , não tem
representação em tempo de execução, mas é significativo para TypeScript. Para o sistema de tipo, StringNumberPair
descreve matrizes cujo índice 0 contém uma string e cujo índice 1 contém um número .

Página 97

function doSomething ( pair : [ string , número ]) {


const a = par [ 0 ];

const a: string

https://translate.googleusercontent.com/translate_f 74/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
const b = par [ 1 ];

const b: número

// ...
}

doSomething ([ "olá" , 42 ]);

Se tentarmos indexar além do número de elementos, obteremos um erro.

function doSomething ( pair : [ string , número ]) {


// ...

const c = par [ 2 ];

O
O tipo
tipo de
de tupla
tupla '[string,
'[string, número]'
número]' de
de comprimento
comprimento '2'
'2' não
não tem
tem nenhum
nenhum elemento
elemento no
no índice
índice '2'.
'2'.

Nós também podemos desestruture tuplas usando a desestruturação de array do JavaScript.

function doSomething ( stringHash : [ string , número ]) {


const [ inputString , hash ] = stringHash ;

console . log ( inputString );

const inputString: string

console . log ( hash );

const hash: number

Página 98

Os tipos de tupla são úteis em APIs baseadas em convenções, onde o significado de cada elemento é "óbvio". Esse

nos dá flexibilidade em tudo o que queremos nomear nossas variáveis ​quando as desestruturamos. No acima

Por exemplo, fomos capazes de nomear os elementos 0 e 1 para o que quiséssemos.

No entanto, como nem todos os usuários têm a mesma visão do que é óbvio, pode valer a pena reconsiderar

se usar objetos com nomes de propriedade descritivos pode ser melhor para sua API.

Além dessas verificações de comprimento, tipos de tupla simples como esses são equivalentes a tipos que são
versões de Array s que declaram propriedades para índices específicos e que declaram comprimento com um
tipo literal numérico.

interface StringNumberPair {
// propriedades especializadas
comprimento : 2 ;
0 : string ;
1 : número ;

// Outro 'Array <string | número> 'membros ...


slice ( start ?: number , end ?: number ): Array < string | número >;

https://translate.googleusercontent.com/translate_f 75/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Outra coisa em que você pode estar interessado é que as tuplas podem ter propriedades opcionais, escrevendo um
ponto de interrogação ( ? após o tipo de um elemento). Elementos de tupla opcionais só podem vir no final, e
também afetam o tipo de comprimento .

digite Either2dOr3d = [ número , número , número ?];

function setCoordinate ( coord : Either2dOr3d ) {


const [ x , y , z ] = coord ;

const z: número | Indefinido

console . log ( `As coordenadas fornecidas tinham $ { coord . length } dimensões` );

(propriedade) comprimento: 2 | 3

Página 99
As tuplas também podem ter elementos de repouso, que devem ser do tipo array / tupla.

digite StringNumberBooleans = [ string , número , ... boolean []];


digite StringBooleansNumber = [ string , ... boolean [], número ];
digite BooleansStringNumber = [... boolean [], string , número ];

StringNumberBooleans descreve uma tupla cujos primeiros dois elementos são string e número
respectivamente, mas que pode ter qualquer número de booleanos a seguir.

StringBooleansNumber descreve uma tupla cujo primeiro elemento é string e depois qualquer
número de booleanos e terminando com um número .

BooleansStringNumber descreve uma tupla cujos elementos iniciais qualquer número de s booleanos
e terminando com uma string e um número .

Uma tupla com um elemento resto não tem "comprimento" definido - ela só tem um conjunto de elementos bem conhecidos em
posições diferentes.

const a : StringNumberBooleans = [ "olá" , 1 ];


const b : StringNumberBooleans = [ "lindo" , 2 , verdadeiro ];
const c : StringNumberBooleans = [ "mundo" , 3 , verdadeiro , falso , verdadeiro , falso , verdadeiro

Por que os elementos opcionais e restantes podem ser úteis? Bem, isso permite que o TypeScript corresponda às tuplas
com listas de parâmetros. Tipos de tuplas podem ser usados ​emparâmetros e argumentos restantes , de modo que o
Segue:

function readButtonInput (... args : [ string , número , ... boolean []]) {


const [ nome , versão , ... entrada ] = argumentos ;
// ...
}

https://translate.googleusercontent.com/translate_f 76/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

é basicamente equivalente a:

function readButtonInput ( nome : string , versão : número , ... input : boolean [


// ...
}

Página 100
Isso é útil quando você deseja obter um número variável de argumentos com um parâmetro resto, e
você precisa de um número mínimo de elementos, mas não quer introduzir variáveis ​intermediárias.

Tipos de tupla somente leitura

Uma nota final sobre os tipos de tupla - os tipos de tupla têm variantes somente leitura e podem ser especificados por
colocando um modificador somente leitura na frente deles - assim como com a sintaxe abreviada de array.

function doSomething ( pair : readonly [ string , number ]) {


// ...
}

Como você pode esperar, gravar em qualquer propriedade de uma tupla somente leitura não é permitido no TypeScript.

function doSomething ( pair : readonly [ string , number ]) {


par [ 0 ] = "olá!" ;

Não
Não éé possível
possível atribuir
atribuir aa '0'
'0' porque
porque éé uma
uma propriedade
propriedade somente
somente leitura.
leitura.

Tuplas tendem a ser criadas e deixadas sem modificações na maioria dos códigos, portanto, os tipos de anotação como somente leitura
tuplas quando possível é um bom padrão. Isso também é importante, dado que literais de matriz com const
asserções serão inferidas com tipos de tupla somente leitura .

deixe ponto = [ 3 , 4 ] como const ;

function distanceFromOrigin ([ x , y ]: [ número , número ]) {


return Math . sqrt ( x ** 2 + y ** 2 );
}

distanceFromOrigin ( ponto );

O
O argumento
argumento do
do tipo
tipo 'somente
'somente leitura
leitura [3,
[3, 4]'
4]' não
não épode
atribuível
ser atribuído
ao parâmetro
ao parâmetro
de do tipo
digite
'[número,
'[número,
número]'.
número]'.
O
O tipo
tipo 'somente
'somente leitura
leitura [3,
[3, 4]'
4]' éé 'somente
'somente leitura'
leitura' ee não
não pode
pode ser
ser atribuído
atribuído aao
otipo
tipomutável
mutável'[número,
'[número,número]'.
número]'.

Página 101
Aqui, distanceFromOrigin nunca modifica seus elementos, mas espera uma tupla mutável. Desde a
https://translate.googleusercontent.com/translate_f 77/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

o tipo do ponto foi inferido como somente leitura [3, 4] , não será compatível com [número,
número], pois esse tipo não pode garantir que os elementos do ponto não sofram mutação.

Página 102

Criação de tipos a partir de tipos

O sistema de tipos do TypeScript é muito poderoso porque permite expressar tipos em termos de outros
tipos.

A forma mais simples dessa ideia são os genéricos; na verdade, temos uma grande variedade de operadores de tipo
Disponível para uso. Também é possível expressar tipos em termos de valores que já temos.

Ao combinar vários operadores de tipo, podemos expressar operações e valores complexos de forma sucinta,
maneira sustentável. Nesta seção, cobriremos maneiras de expressar um novo tipo em termos de um tipo existente
ou valor.

Genéricos - Tipos que levam parâmetros

https://translate.googleusercontent.com/translate_f 78/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Operador Keyof Type - Usando o operador keyof para criar novos tipos
Operador Typeof Type - Usando o operador typeof para criar novos tipos

Tipos de acesso indexados - usando a sintaxe de tipo ['a'] para acessar um subconjunto de um tipo

Tipos condicionais - tipos que agem como instruções if no sistema de tipos

Tipos mapeados - Criação de tipos mapeando cada propriedade em um tipo existente

Tipos literais de modelo - tipos mapeados que alteram propriedades por meio de strings literais de modelo

Página 103

Genéricos

Uma parte importante da engenharia de software é construir componentes que não apenas sejam bem definidos e
APIs consistentes, mas também reutilizáveis. Componentes que são capazes de trabalhar com os dados de hoje
assim como os dados de amanhã darão a você os recursos mais flexíveis para a construção de grandes
sistemas de software.

Em linguagens como C # e Java, uma das principais ferramentas na caixa de ferramentas para criar reutilizáveis
componentes é genérico, ou seja, ser capaz de criar um componente que pode funcionar em uma variedade de
tipos em vez de um único. Isso permite que os usuários consumam esses componentes e usem seus próprios
tipos.

Hello World of Generics


Para começar, vamos fazer o "hello world" dos genéricos: a função de identidade. A função de identidade é um
que retornará tudo o que for passado. Você pode pensar nisso de maneira semelhante ao
comando echo .

Sem os genéricos, teríamos que dar à função de identidade um tipo específico:

identidade da função ( arg : número ): número {


return arg ;
}

Ou podemos descrever a função de identidade usando qualquer tipo:

https://translate.googleusercontent.com/translate_f 79/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

identidade da função ( arg : qualquer ): qualquer {


return arg ;
}

Embora o uso de any seja certamente genérico, pois fará com que a função aceite todo e qualquer tipo de
o tipo de arg , na verdade estamos perdendo as informações sobre o que aquele tipo era quando a função
retorna. Se passarmos um número, a única informação que temos é que qualquer tipo pode ser retornado.

Em vez disso, precisamos de uma maneira de capturar o tipo de argumento de tal forma que também possamos usá-lo
para denotar o que está sendo retornado. Aqui, vamos usar uma variável de tipo, um tipo especial de variável que
funciona em tipos em vez de valores.

Página 104

identidade da função < Tipo > ( arg : Tipo ): Tipo {


return arg ;
}

Agora adicionamos uma variável de tipo Type à função de identidade. Este tipo nos permite capturar o
digite o usuário fornece (por exemplo, número ), para que possamos usar essa informação mais tarde. Aqui, usamos Type
novamente como o tipo de retorno. Na inspeção, podemos ver agora que o mesmo tipo é usado para o argumento e
o tipo de retorno. Isso nos permite trafegar esse tipo de informação em um lado da função e fora do
de outros.

Dizemos que esta versão da função de identidade é genérica, pois funciona em uma variedade de tipos.
Ao contrário de qualquer um , também é tão preciso (ou seja, não perde nenhuma informação) quanto a primeira identidade
função que usa números para o argumento e tipo de retorno.

Depois de escrever a função de identidade genérica, podemos chamá-la de uma das duas maneiras. A primeira maneira é
passe todos os argumentos, incluindo o argumento de tipo, para a função:

let output = identity < string > ( "myString" );

deixe a saída: string

Aqui nós definir explicitamente Tipo para ser corda como um dos argumentos para a chamada de função, denotado
usando <> ao redor dos argumentos em vez de () .

A segunda forma também é talvez a mais comum. Aqui usamos inferência de argumento de tipo - isto é,
queremos que o compilador defina o valor de Type para nós automaticamente com base no tipo de
argumento que passamos em:

let output = identity ( "myString" );

deixe a saída: string

Observe que não precisamos passar explicitamente o tipo nos colchetes angulares ( <> ); o compilador apenas
olhou para o valor "myString" e defina Type para seu tipo. Enquanto a inferência de argumento de tipo pode ser um
ferramenta útil para manter o código mais curto e legível, você pode precisar passar explicitamente o tipo

https://translate.googleusercontent.com/translate_f 80/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 105
argumentos como fizemos no exemplo anterior, quando o compilador falha em inferir o tipo, como pode
acontecem em exemplos mais complexos.

Trabalhando com Variáveis ​de Tipo Genérico


Quando você começar a usar genéricos, notará que, ao criar funções genéricas como
identidade , o compilador irá forçar que você use quaisquer parâmetros digitados genericamente no corpo de
a função corretamente. Ou seja, você realmente trata esses parâmetros como se eles pudessem ser todos e quaisquer
tipos.

Vamos pegar nossa função de identidade anterior:

identidade da função < Tipo > ( arg : Tipo ): Tipo {


return arg ;
}

E se quisermos também registrar o comprimento do argumento arg no console a cada chamada? Nós
pode ficar tentado a escrever isto:

function loggingIdentity < Type > ( arg : Type ): Type {


console . log ( comprimento do arg . );

A
A propriedade
propriedade 'comprimento'
'comprimento' não
não existe
existe no
no tipo
tipo 'Tipo'.
'Tipo'.

return arg ;
}

Quando o fizermos, o compilador nos dará um erro de que estamos usando o membro .length de arg , mas
em nenhum lugar dissemos que arg tem esse membro. Lembre-se, dissemos anteriormente que esse tipo
variáveis ​representam todo e qualquer tipo, então alguém usando esta função poderia ter passado um
número em vez disso, que não tem um membro .length .

Digamos que pretendemos realmente que esta função funcione em matrizes de tipo em vez de tipo
diretamente. Como estamos trabalhando com matrizes, o membro .length deve estar disponível. Nós podemos
descreva isso da mesma forma que criaríamos matrizes de outros tipos:

Página 106

function loggingIdentity < Type > ( arg : Type []): Type [] {


console . log ( comprimento do arg . );
return arg ;
}

Você pode ler o tipo de loggingIdentity como "a função genérica loggingIdentity leva um
type parâmetro Type e um argumento arg que é uma matriz de Type s e retorna uma matriz de

Digite s. "Se passássemos uma matriz de números, obteríamos uma matriz de números de volta, como Tipo

https://translate.googleusercontent.com/translate_f 81/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
se ligaria ao número . Isso nos permite usar nossa variável de tipo genérico Type como parte dos tipos
estamos trabalhando com, em vez de todo o tipo, dando-nos maior flexibilidade.

Podemos, alternativamente, escrever o exemplo de exemplo desta maneira:

function loggingIdentity < Type > ( arg : Array < Type >): Array < Type > {
console . log ( comprimento do arg . ); // Array tem um .length, então não há mais erros
return arg ;
}

Você já deve estar familiarizado com esse estilo de tipo em outras línguas. Na próxima seção, vamos
cobrir como você pode criar seus próprios tipos genéricos como Array <Type> .

Tipos Genéricos
Nas seções anteriores, criamos funções de identidade genéricas que funcionavam em uma variedade de tipos. Nisso
seção, exploraremos o tipo das próprias funções e como criar interfaces genéricas.

O tipo de funções genéricas é igual ao das funções não genéricas, com os parâmetros de tipo
listados primeiro, de forma semelhante às declarações de função:

identidade da função < Tipo > ( arg : Tipo ): Tipo {


return arg ;
}

let myIdentity : < Type > ( arg : Type ) => Type = identity ;

Página 107
Também poderíamos ter usado um nome diferente para o parâmetro de tipo genérico no tipo, desde que o
número de variáveis ​de tipo e como as variáveis ​de tipo são usadas alinham.

identidade da função < Tipo > ( arg : Tipo ): Tipo {


return arg ;
}

let myIdentity : < Input > ( arg : Input ) => Input = identity ;

Também podemos escrever o tipo genérico como uma assinatura de chamada de um tipo literal de objeto:

identidade da função < Tipo > ( arg : Tipo ): Tipo {


return arg ;
}

let myIdentity : {< Type > ( arg : Type ): Type } = identidade ;

O que nos leva a escrever nossa primeira interface genérica. Vamos pegar o objeto literal do anterior
exemplo e mova-o para uma interface:

interface GenericIdentityFn {

https://translate.googleusercontent.com/translate_f 82/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
< Tipo > ( arg : Tipo ): Tipo ;
}

identidade da função < Tipo > ( arg : Tipo ): Tipo {


return arg ;
}

deixe myIdentity : GenericIdentityFn = identidade ;

Em um exemplo semelhante, podemos querer mover o parâmetro genérico para ser um parâmetro de todo
interface. Isso nos permite ver que tipo (s) somos genéricos (por exemplo, Dicionário <string> ao invés de
apenas Dicionário ). Isso torna o parâmetro de tipo visível para todos os outros membros da interface.

Página 108

interface GenericIdentityFn < Type > {


( arg : Tipo ): Tipo ;
}

identidade da função < Tipo > ( arg : Tipo ): Tipo {


return arg ;
}

deixe myIdentity : GenericIdentityFn < número > = identidade ;

Observe que nosso exemplo mudou para algo ligeiramente diferente. Em vez de descrever um
função genérica, agora temos uma assinatura de função não genérica que faz parte de um tipo genérico.
Quando usamos GenericIdentityFn , agora também precisamos especificar o tipo correspondente
(aqui: número ), travando efetivamente o que a assinatura de chamada subjacente usará.
Compreender quando colocar o parâmetro de tipo diretamente na assinatura de chamada e quando colocá-lo
a própria interface será útil para descrever quais aspectos de um tipo são genéricos.

Além de interfaces genéricas, também podemos criar classes genéricas. Observe que não é possível
criar enums e namespaces genéricos.

Classes Genéricas
Uma classe genérica tem uma forma semelhante a uma interface genérica. Classes genéricas têm um tipo genérico
lista de parâmetros entre colchetes angulares ( <> ) após o nome da classe.

class GenericNumber < NumType > {


zeroValue : NumType ;
adicionar : ( x : NumType , y : NumType ) => NumType ;
}

deixe myGenericNumber = new GenericNumber < número > ();


myGenericNumber . zeroValue = 0 ;
myGenericNumber . add = function ( x , y ) {
retornar x + y ;
};

https://translate.googleusercontent.com/translate_f 83/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Este é um uso bastante literal da classe GenericNumber , mas você deve ter notado que nada é
restringindo-o para usar apenas o tipo de número . Poderíamos ter usado string ou ainda mais

Página 109
objetos complexos.

deixe stringNumeric = new GenericNumber < string > ();


stringNumeric . zeroValue = "" ;
stringNumeric . add = function ( x , y ) {
retornar x + y ;
};

console . log ( stringNumeric . add ( stringNumeric . zeroValue , "teste" ));

Assim como com a interface, colocar o parâmetro de tipo na própria classe nos permite ter certeza de que todos os
propriedades da classe estão trabalhando com o mesmo tipo.

Enquanto cobrimos em nossa seção sobre aulas, uma classe tem dois lados para seu tipo: o lado estático e o
lado da instância. As classes genéricas são genéricas apenas em seu lado da instância, e não no lado estático,
portanto, ao trabalhar com classes, os membros estáticos não podem usar o parâmetro de tipo da classe.

Restrições Genéricas
Se você se lembra de um exemplo anterior, às vezes você pode querer escrever uma função genérica que
trabalha em um conjunto de tipos onde você tem algum conhecimento sobre quais recursos esse conjunto de tipos
terá. Em nosso exemplo de loggingIdentity , queríamos ser capazes de acessar o .length
de arg , mas o compilador não conseguiu provar que cada tipo tinha uma propriedade .length , então
nos avisa que não podemos fazer essa suposição.

function loggingIdentity < Type > ( arg : Type ): Type {


console . log ( comprimento do arg . );

A
A propriedade
propriedade 'comprimento'
'comprimento' não
não existe
existe no
no tipo
tipo 'Tipo'.
'Tipo'.

return arg ;
}

Em vez de trabalhar com todo e qualquer tipo, gostaríamos de restringir esta função para funcionar com qualquer e
todos os tipos que também têm a propriedade .length . Contanto que o tipo tenha esse membro, vamos permitir,
mas é necessário ter pelo menos este membro. Para fazer isso, devemos listar nosso requisito como uma restrição
em que tipo pode ser.

Para fazer isso, criaremos uma interface que descreve nossa restrição. Aqui, vamos criar uma interface que
tem uma única propriedade .length e então usaremos essa interface e a palavra-chave extends para

Página 110
denotam nossa restrição:

interface Lengthwise {
comprimento : número ;
}

https://translate.googleusercontent.com/translate_f 84/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

function loggingIdentity < Type extends Lengthwise > ( arg : Type ): Type {
console . log ( comprimento do arg . ); // Agora sabemos que ele tem uma propriedade .length, então não
return arg ;
}

Como a função genérica agora está restrita, ela não funcionará mais em todos os tipos:

loggingIdentity ( 3 );

O
O argumento
argumento do
do tipo
tipo 'número'
'número' não
não éé atribuível
atribuível ao
ao parâmetro
parâmetro do
do tipo
tipo
'Longitudinalmente'.
'Longitudinalmente'.

Em vez disso, precisamos passar valores cujo tipo tenha todas as propriedades necessárias:

loggingIdentity ({ comprimento: 10 , valor: 3 });

Usando parâmetros de tipo em restrições genéricas


Você pode declarar um parâmetro de tipo que é restringido por outro parâmetro de tipo. Por exemplo aqui
gostaríamos de obter uma propriedade de um objeto dado seu nome. Gostaríamos de garantir que não estamos
pegando acidentalmente uma propriedade que não existe no obj , então colocaremos uma restrição entre
os dois tipos:

Página 111

function getProperty < Type , Key extends keyof Type > ( obj : Type , key : Key ) {
return obj [ chave ];
}

seja x = { a: 1 , b: 2 , c: 3 , d: 4 };

getProperty ( x , "a" );
getProperty ( x , "m" );

O
O argumento
argumento do
do tipo
tipo '"m"'
'"m"' não
não éé atribuível
atribuível ao
ao parâmetro
parâmetro do
do tipo
tipo '"a"
'"a" || "b" |
"b"
"c" | "c"
"d" |'."d" '.

Usando tipos de classe em genéricos


Ao criar fábricas no TypeScript usando genéricos, é necessário referir-se aos tipos de classe por seus
funções de construtor. Por exemplo,

https://translate.googleusercontent.com/translate_f 85/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
função criar < Tipo > ( c : { novo (): Tipo }): Tipo {
retornar novo c ();
}

Um exemplo mais avançado usa a propriedade prototype para inferir e restringir relacionamentos entre
a função construtora e o lado da instância dos tipos de classe.

Página 112

class BeeKeeper {
hasMask : boolean = true ;
}

class ZooKeeper {
crachá : string = "Mikle" ;
}

class Animal {
numLegs : número = 4 ;
}

classe Bee extends Animal {


goleiro : BeeKeeper = novo BeeKeeper ();
}

classe Lion extends Animal {


guardião : ZooKeeper = novo ZooKeeper ();
}

função createInstance < Um estende animal > ( c : novo () => A ): A {


retornar novo c ();
}

createInstance ( Lion ). guardião . crachá ;


createInstance ( Bee ). guardião . hasMask ;

Este padrão é usado para alimentar o padrão de design mixins .

https://translate.googleusercontent.com/translate_f 86/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 113

Operador do tipo chave

O operador do tipo keyof


O operador keyof pega um tipo de objeto e produz uma string ou união literal numérica de suas chaves.
O seguinte tipo P é do mesmo tipo que "x" | "y":

tipo ponto = { x : número ; y : número };


tipo P = keyof Ponto ;

tipo P = ponto chave

Se o tipo tiver uma string ou assinatura de índice numérico , o keyof retornará esses tipos:

tipo Arrayish = {[ n : número ]: desconhecido };


tipo A = keyof Arrayish ;

tipo A = número

tipo Mapish = {[ k : string ]: booleano };


tipo M = keyof Mapish ;

tipo M = string | número

Observe que, neste exemplo, M é string | número - isso ocorre porque as chaves do objeto JavaScript são
sempre forçado a uma string, então obj [0] é sempre o mesmo que obj ["0"] .

keyof types tornam-se especialmente úteis quando combinados com tipos mapeados, que aprenderemos mais
sobre mais tarde.

Página 114

https://translate.googleusercontent.com/translate_f 87/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Operador de tipo

O operador typeof type


JavaScript já tem um operador typeof que você pode usar em um contexto de expressão:

// Imprime "string"
console . log ( tipo de "Olá, mundo" );

TypeScript adiciona um operador typeof que você pode usar em um contexto de tipo para se referir ao tipo de uma variável
ou propriedade:

deixe s = "olá" ;
let n : typeof s ;

deixe n: string

Isso não é muito útil para tipos básicos, mas combinado com outros operadores de tipo, você pode usar typeof
para expressar convenientemente muitos padrões. Por exemplo, vamos começar examinando o tipo predefinido
ReturnType <T> . Ele pega um tipo de função e produz seu tipo de retorno:

tipo Predicado = ( x : desconhecido ) => booleano ;


tipo K = ReturnType < Predicado >;

tipo K = booleano

Se tentarmos usar ReturnType em um nome de função, veremos um erro instrutivo:

Página 115

function f () {
return { x: 10 , y: 3 };
}
tipo P = ReturnType < f >;

'f'
'f' refere-se
refere-se aa um
um valor,
valor, mas
mas está
está sendo
sendo usado
usado como
como um
um tipo
tipo aqui.
aqui. Você
Você quis
quis dizer
dizer
'tipo
'tipo de
de f'?
f'?

Lembre-se de que valores e tipos não são a mesma coisa. Para se referir ao tipo que o valor f tem, nós
use typeof :

function f () {
return { x: 10 , y: 3 };

https://translate.googleusercontent.com/translate_f 88/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
}
tipo P = ReturnType < typeof f >;

tipo P = {
x: número;
y: número;
}

Limitações

O TypeScript limita intencionalmente os tipos de expressões que você pode usar no tipo typeof .

Especificamente, só é legal usar typeof em identificadores (ou seja, nomes de variáveis) ou em suas propriedades. Esse
ajuda a evitar a armadilha confusa de escrever código que você acha que está executando, mas não está:

// Pretendia usar = ReturnType <typeof msgbox>


let shouldContinue : typeof msgbox ( "Tem certeza que deseja continuar?" );

','',' esperado.
esperado.

Página 116

Tipos de acesso indexados

Podemos usar um tipo de acesso indexado para pesquisar uma propriedade específica em outro tipo:

tipo Pessoa = { idade : número ; nome : string ; vivo : booleano };


tipo Idade = Pessoa [ "idade" ];

tipo Idade = número

O tipo de indexação em si é um tipo, então podemos usar unions, keyof ou outros tipos inteiramente:

tipo I1 = Pessoa [ "idade" | "nome" ];

tipo I1 = string | número

tipo I2 = Pessoa [ tecla de Pessoa ];

tipo I2 = string | número | boleano

digite AliveOrName = "vivo" | "nome" ;


tipo I3 = Pessoa [ AliveOrName ];

tipo I3 = string | boleano

https://translate.googleusercontent.com/translate_f 89/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Você até verá um erro se tentar indexar uma propriedade que não existe:

tipo I1 = Pessoa [ "alve" ];

A
A propriedade
propriedade 'alve'
'alve' não
não existe
existe no
no tipo
tipo 'Person'.
'Person'.

Outro exemplo de indexação com um tipo arbitrário é usar o número para obter o tipo de um array
elementos Podemos combinar isso com typeof para capturar convenientemente o tipo de elemento de uma matriz

Página 117
literal:

const MyArray = [
{ nome: "Alice" , idade: 15 },
{ nome: "Bob" , idade: 23 },
{ nome: "Eva" , idade: 38 },
];

digite Person = typeof MyArray [ número ];

tipo Person = {
nome: string;
idade: número;
}

type Age = typeof MyArray [ número ] [ "idade" ];

tipo Idade = número

// Ou
tipo Idade2 = Pessoa [ "idade" ];

tipo Age2 = number

Você só pode usar tipos ao indexar, o que significa que você não pode usar um const para fazer uma variável
referência:

chave const = "idade" ;


tipo Idade = Pessoa [ tecla ];

O
O tipo
tipo 'chave'
'chave' não
não pode
pode ser
ser usado
usado como
como um
um tipo
tipo de
de índice.
índice.
'chave'
'chave' refere-se
refere-se aa um
um valor,
valor, mas
mas está
está sendo
sendo usado
usado como
como um
um tipo
tipo aqui.
aqui. Você
Você quis
quis dizer
dizer
'tipo
'tipo de
de chave'?
chave'?

No entanto, você pode usar um alias de tipo para um estilo semelhante de refatoração:

chave de tipo = "idade" ;


tipo Idade = Pessoa [ tecla ];

https://translate.googleusercontent.com/translate_f 90/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 119
118

Tipos condicionais

No cerne da maioria dos programas úteis, temos que tomar decisões com base nas informações fornecidas. JavaScript
programas não são diferentes, mas dado o fato de que os valores podem ser facilmente introspectados, essas decisões
também se baseiam nos tipos de entradas. Tipos condicionais ajudam a descrever a relação entre o
tipos de entradas e saídas.

interface Animal {
vivo (): vazio ;
}
interface Dog extends Animal {
trama (): vazio ;
}

tipo Example1 = Cachorro extende Animal ? número : string ;

tipo Exemplo1 = número

tipo Exemplo2 = RegExp extends Animal ? número : string ;

tipo Example2 = string

Os tipos condicionais assumem uma forma que se parece um pouco com expressões condicionais ( condição?

trueExpression: falseExpression ) em JavaScript:

SomeType estende OtherType ? TrueType : FalseType ;

Quando o tipo do lado esquerdo do estende é atribuído para o outro à direita, então você vai ter a
digite na primeira ramificação (a ramificação "verdadeira"); caso contrário, você obterá o tipo no último ramo (o
ramo "falso").

A partir dos exemplos acima, os tipos condicionais podem não parecer imediatamente úteis - podemos dizer
se o cão estende ou não o animal e escolhe o número ou a corda ! Mas o poder de
tipos condicionais vêm de usá-los com genéricos.

Por exemplo, vamos usar a seguinte função createLabel :

Página 120

interface IdLabel {
id : número / * alguns campos * / ;
}
interface NameLabel {
nome : string / * outros campos * / ;
}

função createLabel ( id : número ): IdLabel ;


função createLabel ( nome : string ): NameLabel ;
function createLabel ( nameOrId : string | number ): IdLabel | NameLabel ;
function createLabel ( nameOrId : string | number ): IdLabel | NameLabel {

https://translate.googleusercontent.com/translate_f 91/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
lance "não implementado" ;
}

Essas sobrecargas para createLabel descrevem uma única função JavaScript que faz uma escolha com base em
os tipos de suas entradas. Observe algumas coisas:

1. Se uma biblioteca tiver que fazer o mesmo tipo de escolha repetidamente em toda a sua API, este
torna-se complicado.
2. Temos que criar três sobrecargas: uma para cada caso, quando tivermos certeza do tipo (uma para
string e um para número ), e um para o caso mais geral (pegando uma string |
número ). Para cada novo tipo que o createLabel pode manipular, o número de sobrecargas aumenta
exponencialmente.

Em vez disso, podemos codificar essa lógica em um tipo condicional:

tipo NameOrId < T extends number | string > = T estende o número


? IdLabel
: NameLabel ;

Podemos então usar esse tipo condicional para simplificar nossas sobrecargas em uma única função sem
sobrecargas.

Página 121

função createLabel < T extends number | string > ( idOrName : T ): NameOrId < T >
lance "não implementado" ;
}

deixe a = createLabel ( "typescript" );

deixe um: NameLabel

deixe b = criarLabel ( 2.8 );

deixe b: IdLabel

deixe c = createLabel ( Math . random ()? "olá" : 42 );

deixe c: NameLabel | IdLabel

Restrições de tipo condicional

Freqüentemente, as verificações em um tipo condicional nos fornecem algumas informações novas. Assim como com
estreitar com protetores de tipo pode nos dar um tipo mais específico, o verdadeiro ramo de um tipo condicional
restringirá ainda mais os genéricos pelo tipo que verificamos.

https://translate.googleusercontent.com/translate_f 92/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Por exemplo, vamos pegar o seguinte:

digite MessageOf < T > = T [ "mensagem" ];

O
O tipo
tipo '"mensagem"'
'"mensagem"' não
não pode
pode ser
ser usado
usado para
para indexar
indexar oo tipo
tipo 'T'.
'T'.

Neste exemplo, erros de TypeScript porque T não é conhecido por ter uma propriedade chamada mensagem . Nós
poderia restringir T , e o TypeScript não reclamaria mais:

Página 122

digite MessageOf < T extends { message : unknown }> = T [ "mensagem" ];

interface Email {
mensagem : string ;
}

digite EmailMessageContents = MessageOf < Email >;

tipo EmailMessageContents = string

No entanto, e se quiséssemos que MessageOf tomasse qualquer tipo, e o padrão para algo como nunca se um

a propriedade da mensagem não está disponível? Podemos fazer isso removendo a restrição e introduzindo um
tipo condicional:

tipo MessageOf < T > = T estende { mensagem : desconhecido }? T [ "mensagem" ]: nunca ;

interface Email {
mensagem : string ;
}

interface Dog {
casca (): vazio ;
}

digite EmailMessageContents = MessageOf < Email >;

tipo EmailMessageContents = string

digite DogMessageContents = MessageOf < Dog >;

tipo DogMessageContents = never

No ramo verdadeiro, o TypeScript sabe que T terá uma propriedade de mensagem .

Como outro exemplo, também poderíamos escrever um tipo chamado Flatten que nivela os tipos de array para seus
https://translate.googleusercontent.com/translate_f 93/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

tipos de elemento, mas os deixa sozinhos de outra forma:

Página 123

tipo Flatten < T > = T estende qualquer []? T [ número ]: T ;

// Extrai o tipo de elemento.


tipo Str = Flatten < string []>;

tipo Str = string

// Deixa o tipo sozinho.


tipo Num = Flatten < número >;

tipo Num = número

Quando Flatten recebe um tipo de array, ele usa um acesso indexado com número para buscar

tipo de elemento de string [] . Caso contrário, ele apenas retorna o tipo que foi fornecido.

Inferindo dentro de tipos condicionais

Acabamos de usar tipos condicionais para aplicar restrições e, em seguida, extrair os tipos.
Isso acaba sendo uma operação tão comum que os tipos condicionais a tornam mais fácil.

Os tipos condicionais nos fornecem uma maneira de inferir a partir dos tipos com os quais comparamos na verdadeira ramificação
usando a palavra-chave infer . Por exemplo, poderíamos ter inferido o tipo de elemento em Flatten
em vez de buscá-lo "manualmente" com um tipo de acesso indexado:

tipo Flatten < Type > = Type extends Array < inferir Item >? Item : Tipo ;

Aqui, usamos a palavra-chave infer para apresentar declarativamente uma nova variável de tipo genérico chamada

Item em vez de especificar como recuperar o tipo de elemento de T no ramo verdadeiro. Isso libera
temos que pensar sobre como cavar e sondar a estrutura dos tipos
estamos interessados.

Podemos escrever alguns apelidos de tipo auxiliar úteis usando a palavra-chave infer . Por exemplo, para simples
casos, podemos extrair o tipo de retorno dos tipos de função:

Página 124

tipo GetReturnType < Type > = Type extends (... args : never []) => inferir Return
? Retornar
: nunca ;

tipo Num = GetReturnType <() => número >;

https://translate.googleusercontent.com/translate_f 94/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
tipo Num = número

tipo Str = GetReturnType <( x : string ) => string >;

tipo Str = string

type Bools = GetReturnType <( a : boolean , b : boolean ) => boolean []>;

tipo Bools = boolean []

Ao inferir de um tipo com várias assinaturas de chamada (como o tipo de um


função), as inferências são feitas a partir da última assinatura (que, presumivelmente, é a mais permissiva
caso abrangente). Não é possível realizar a resolução de sobrecarga com base em uma lista de tipos de argumento.

declara a função stringOuNum ( x : string ): número ;


declara a função stringOuNum ( x : número ): string ;
declara a função stringOrNum ( x : string | número ): string | número ;

tipo T1 = ReturnType < typeof stringOrNum >;

tipo T1 = string | número

Tipos Condicionais Distributivos


Quando os tipos condicionais agem em um tipo genérico, eles se tornam distributivos quando recebem um tipo de união.
Por exemplo, tome o seguinte:

tipo ToArray < Type > = Type extends any ? Tipo []: nunca ;

Página 125
Se conectarmos um tipo de união em ToArray , o tipo condicional será aplicado a cada membro de
essa união.

tipo ToArray < Type > = Type extends any ? Tipo []: nunca ;

digite StrArrOrNumArr = ToArray < string | número >;

tipo StrArrOrNumArr = string [] | número[]

O que acontece aqui é que StrArrOrNumArr distribui em:

string | número ;

e mapeia cada tipo de membro do sindicato, para o que é efetivamente:

ToArray < string > | ToArray < número >;


https://translate.googleusercontent.com/translate_f 95/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

o que nos deixa com:

string [] | número [];

Normalmente, a distributividade é o comportamento desejado. Para evitar esse comportamento, você pode cercar cada lado do
a palavra-chave extends com colchetes.

tipo ToArrayNonDist < Type > = [ Type ] extends [ any ]? Tipo []: nunca ;

// 'StrArrOrNumArr' não é mais uma união.


digite StrArrOrNumArr = ToArrayNonDist < string | número >;

tipo StrArrOrNumArr = (string | número) []

Página 127
126

Tipos mapeados

Quando você não quer se repetir, às vezes um tipo precisa ser baseado em outro tipo.

Os tipos mapeados baseiam-se na sintaxe para assinaturas de índice, que são usadas para declarar os tipos de
propriedades que não foram declaradas com antecedência:

tipo OnlyBoolsAndHorses = {
[ chave : string ]: booleano | Cavalo ;
};

const está em conformidade : OnlyBoolsAndHorses = {


del: true ,
rodney: falso ,
};

Um tipo mapeado é um tipo genérico que usa uma união de PropertyKey s (frequentemente criado por meio de um
keyof ) para iterar por meio de chaves para criar um tipo:

tipo OptionsFlags < Type > = {


[ Propriedade no tipo keyof ]: booleano ;
};

Neste exemplo, OptionsFlags pegará todas as propriedades do tipo Type e mudará seus
valores para ser um booleano.

https://translate.googleusercontent.com/translate_f 96/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 128

tipo FeatureFlags = {
darkMode : () => vazio ;
newUserProfile : () => void ;
};

digite FeatureOptions = OptionsFlags < FeatureFlags >;

tipo FeatureOptions = {
darkMode: boolean;
newUserProfile: boolean;
}

Modificadores de mapeamento

Existem dois modificadores adicionais que podem ser aplicados durante o mapeamento: somente leitura e ? que
afetam mutabilidade e opcionalidade, respectivamente.

Você pode remover ou adicionar esses modificadores prefixando com - ou + . Se você não adicionar um prefixo, então +
é assumido.

// Remove atributos 'somente leitura' das propriedades de um tipo


tipo CreateMutable < Type > = {
- somente leitura [ Propriedade na chave do Tipo ]: Tipo [ Propriedade ];
};

tipo LockedAccount = {
id somente leitura : string ;
nome somente leitura : string ;
};

digite UnlockedAccount = CreateMutable < LockedAccount >;

digite UnlockedAccount = {
id: string;
nome: string;
}

Página 129

// Remove atributos 'opcionais' das propriedades de um tipo

https://translate.googleusercontent.com/translate_f 97/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
tipo concreto < tipo > = {
[ Property in keyof Type ] - ?: Type [ Property ];
};

tipo MaybeUser = {
id : string ;
nome ?: string ;
idade ?: número ;
};

tipo Usuário = Concreto < MaybeUser >;

tipo User = {
id: string;
nome: string;
idade: número;
}

Remapeamento de chave via como


À máquina 4.1 em diante, você pode voltar a mapear as teclas em tipos mapeados com um como cláusula de um
tipo mapeado:

tipo MappedTypeWithNewProperties < Type > = {


[ Propriedades em keyof Digite como NewKeyType ]: Digite [ Propriedades ]
}

Você pode aproveitar recursos como tipos literais de modelo para criar novos nomes de propriedade a partir dos anteriores:

Página 130

tipo Getters < Type > = {


[ Propriedade em keyof Digite como `get $ { Capitalize < string & Property > } ` ]: ()
};

interface Person {
nome : string ;
idade : número ;
localização : string ;
}

digite LazyPerson = Getters < Pessoa >;

tipo LazyPerson = {
getName: () => string;
getAge: () => número;
getLocation: () => string;

https://translate.googleusercontent.com/translate_f 98/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
}

Você pode filtrar as chaves produzindo nunca por meio de um tipo condicional:

// Remova a propriedade 'kind'


tipo RemoveKindField < Type > = {
[ Propriedade em keyof Type as Exclude < Property , "kind" >]: Type [ Property ]
};

interface Circle {
tipo : "círculo" ;
raio : número ;
}

digite KindlessCircle = RemoveKindField < Circle >;

tipo KindlessCircle = {
raio: número;
}

Você pode mapear uniões arbitrárias, não apenas uniões de string | número | símbolo , mas uniões de
qualquer tipo:

Página 131

tipo EventConfig < Eventos extends { kind : string }> = {


[ E em Eventos como E [ "tipo" ]]: ( evento : E ) => vazio ;
}

digite SquareEvent = { tipo : "quadrado" , x : número , y : número };


digite CircleEvent = { kind : "circle" , radius : number };

tipo Config = EventConfig < SquareEvent | CircleEvent >

tipo Config = {
quadrado: (evento: SquareEvent) => vazio;
círculo: (evento: CircleEvent) => vazio;
}

Exploração Adicional

Os tipos mapeados funcionam bem com outros recursos nesta seção de manipulação de tipo, por exemplo, aqui está um
tipo mapeado usando um tipo condicional que retorna verdadeiro ou falso, dependendo de
se um objeto tem a propriedade pii definida como verdadeiro literal :

digite ExtractPII < Type > = {


[ Property in keyof Type ]: Type [ Property ] extends { pii : true }? verdade :
};

tipo DBFields = {
id : { formato : "incrementando" };
nome : { tipo : string ; pii : verdadeiro };
};

https://translate.googleusercontent.com/translate_f 99/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

digite ObjectsNeedingGDPRDeletion = ExtractPII < DBFields >;

tipo ObjectsNeedingGDPRDeletion = {
id: falso;
nome: verdadeiro;
}

Página 132

Tipos literais de modelo

Tipos literais de modelo baseados em tipos literais de string, e têm a capacidade de se expandir em muitas strings
via sindicatos.

Eles têm a mesma sintaxe que strings literais de modelo em JavaScript, mas são usados ​em posições de tipo.
Quando usado com tipos de literais concretos, um literal de modelo produz um novo tipo de literal de string por
concatenando o conteúdo.

digite mundo = "mundo" ;

digite Saudação = `olá $ { World } ` ;

digite Saudação = "olá, mundo"

Quando uma união é usada na posição interpolada, o tipo é o conjunto de cada literal de string possível
que poderia ser representado por cada membro do sindicato:

digite EmailLocaleIDs = "welcome_email" | "email_heading" ;


tipo FooterLocaleIDs = "footer_title" | "footer_sendoff" ;

tipo AllLocaleIDs = ` $ { EmailLocaleIDs | FooterLocaleIDs } _id` ;

tipo AllLocaleIDs = "welcome_email_id" | "email_heading_id" | "footer_tit

Para cada posição interpolada no literal do modelo, as uniões são multiplicadas em cruz:

tipo AllLocaleIDs = ` $ { EmailLocaleIDs | FooterLocaleIDs } _id` ;


tipo Lang = "en" | "ja" | "pt" ;

digite LocaleMessageIDs = ` $ { Lang } _ $ { AllLocaleIDs } ` ;

tipo LocaleMessageIDs = "en_welcome_email_id" | "en_email_heading_id" | "

https://translate.googleusercontent.com/translate_f 100/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 133
Geralmente recomendamos que as pessoas usem a geração antecipada para grandes uniões de cadeia, mas isso
é útil em casos menores.

Uniões de cordas em tipos

O poder dos literais de modelo vem ao definir uma nova string com base em uma string existente dentro
um tipo.

Por exemplo, um padrão comum em JavaScript é estender um objeto com base nos campos que ele
atualmente tem. Iremos fornecer uma definição de tipo para uma função que adiciona suporte para uma função on
que permite saber quando um valor mudou:

const person = makeWatchedObject ({


primeiroNome: "Saoirse" ,
lastName: "Ronan" ,
idade: 26 ,
});

pessoa . on ( "firstNameChanged" , ( newValue ) => {


console . log ( `firstName foi alterado para $ { newValue } !` );
});

Observe que no escuta o evento "firstNameChanged" , não apenas "firstName" , modelo


literais fornecem uma maneira de lidar com esse tipo de manipulação de string dentro do sistema de tipos:

tipo PropEventSource < Type > = {


on ( eventName : ` $ { string & keyof Type } Changed` , callback : ( newValue : an
};

/// Cria um "objeto vigiado" com um método 'on'


/// para que você possa observar as alterações nas propriedades.
declara a função makeWatchedObject < Type > ( obj : Type ): Type & PropEventSourc

Com isso, podemos construir algo que erre quando dada a propriedade errada:

Página 134

const person = makeWatchedObject ({


primeiroNome: "Saoirse" ,
lastName: "Ronan" ,
idade: 26
});

pessoa . em ( "firstNameChanged" , () => {});

// Evita erros humanos fáceis (usando a chave em vez do nome do evento)


pessoa . em ( "firstName" , () => {});

O
O argumento
argumento do
do tipo
tipo '"firstName"'
'"firstName"' não
não éé atribuível
atribuível ao
ao parâmetro
parâmetro do
do tipo
tipo

https://translate.googleusercontent.com/translate_f 101/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
'"firstNameChanged"
'"firstNameChanged" || "lastNameChanged"
"lastNameChanged" || "ageChanged"
"ageChanged" '.'.

// É resistente a erros de digitação


pessoa . on ( "frstNameChanged" , () => {});

O
O argumento
argumento do
do tipo
tipo '"frstNameChanged"'
'"frstNameChanged"' não
não pode
pode ser
ser atribuído
atribuído ao
ao parâmetro
parâmetro de
de
tipo
tipo '"firstNameChanged"
'"firstNameChanged" || "lastNameChanged"
"lastNameChanged" || "ageChanged"
"ageChanged" '.'.

Inferência com literais de modelo

Observe como os últimos exemplos não reutilizaram o tipo do valor original. O retorno de chamada usou um any .
Os tipos literais de modelo podem ser inferidos a partir de posições de substituição.

Podemos tornar nosso último exemplo genérico para inferir de partes da string eventName para descobrir
a propriedade associada.

Página 135

tipo PropEventSource < Type > = {


em < Key extends string & keyof Type >
( eventName : ` $ { Key } Changed` , callback : ( newValue : Type [ Key ]) => vo
};

declara a função makeWatchedObject < Type > ( obj : Type ): Type & PropEventSourc

const person = makeWatchedObject ({


primeiroNome : "Saoirse" ,
lastName : "Ronan" ,
idade : 26
});

pessoa . em ( "firstNameChanged" , newName => {

(parâmetro) newName: string

console . log ( `novo nome é $ { newName . toUpperCase () } ` );


});

pessoa . on ( "ageChanged" , newAge => {

(parâmetro) newAge: número

if ( newAge <0) {
console . avisar ( "aviso! idade negativa" );
}

https://translate.googleusercontent.com/translate_f 102/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
})

Aqui fizemos em em um método genérico.

Quando um usuário chama com a string "firstNameChanged ' , o TypeScript tentará inferir o tipo correto
para a chave . Para fazer isso, ele irá comparar a chave com o conteúdo antes de "Alterado" e inferir a string

"firstName" . Depois que o TypeScript descobrir isso, o método on pode buscar o tipo de firstName
no objeto original, que é string neste caso. Da mesma forma, quando chamado com "ageChanged" ,
TypeScript encontra o tipo para a idade da propriedade, que é o número .

A inferência pode ser combinada de diferentes maneiras, muitas vezes para desconstruir strings e reconstruí-las em
jeitos diferentes.

Tipos de manipulação intrínseca de strings

Página 136
Para ajudar na manipulação de strings, o TypeScript inclui um conjunto de tipos que podem ser usados ​em strings
manipulação. Esses tipos vêm integrados ao compilador para desempenho e não podem ser encontrados no
Arquivos .d.ts incluídos no TypeScript.

Maiúsculas <StringType>

Converte cada caractere da string na versão em maiúsculas.

Exemplo

digite Saudação = "Olá, mundo"


digite ShoutyGreeting = Maiúscula < Saudação >

digite ShoutyGreeting = "OLÁ, MUNDO"

tipo ASCIICacheKey < Str extends string > = `ID- $ { Maiúsculas < Str > } `
digite MainID = ASCIICacheKey < "my_app" >

digite MainID = "ID-MY_APP"

<StringType> em minúsculas

Converte cada caractere da string no equivalente em minúsculas.

Exemplo

digite Saudação = "Olá, mundo"


tipo QuietGreeting = Minúsculas < Saudação >

tipo QuietGreeting = "olá, mundo"

tipo ASCIICacheKey < Str extends string > = `id- $ { Minúsculas < Str > } `
digite MainID = ASCIICacheKey < "my_app" >

digite MainID = "id-my_app"

https://translate.googleusercontent.com/translate_f 103/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 137

Capitalize <StringType>

Converte o primeiro caractere da string em um equivalente em maiúsculas.

Exemplo

digite LowercaseGreeting = "olá, mundo" ;


digite Saudação = Capitalize < LowercaseGreeting >;

digite Saudação = "Olá, mundo"

Descapitalize <StringType>

Converte o primeiro caractere da string em um equivalente em minúsculas.

Exemplo

digite UppercaseGreeting = "OLÁ, MUNDO" ;


digite UncomfortableGreeting = Uncapitalize < UppercaseGreeting >;

digite UncomfortableGreeting = "hELLO WORLD"

Detalhes técnicos sobre os tipos intrínsecos de manipulação de strings

Página 138

Aulas

TypeScript oferece suporte total para a palavra-chave class introduzida em


Leitura de fundo:
ES2015.
Classes (MDN)

https://translate.googleusercontent.com/translate_f 104/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Tal como acontece com outros recursos da linguagem JavaScript, o TypeScript adiciona o tipo
anotações e outra sintaxe para permitir que você expresse relacionamentos entre classes e outros tipos.

Membros da classe
Aqui está a classe mais básica - uma vazia:

classe Point {}

Esta classe ainda não é muito útil, então vamos começar a adicionar alguns membros.

Campos

Uma declaração de campo cria uma propriedade pública gravável em uma classe:

class Point {
x : número ;
y : número ;
}

const pt = novo Point ();


pt . x = 0 ;
pt . y = 0 ;

Tal como acontece com outros locais, o tipo de anotação é opcional, mas será uma implícita qualquer se não especificado.

Os campos também podem ter inicializadores; eles serão executados automaticamente quando a classe for instanciada:

Página 139

class Point {
x=0;
y=0;
}

const pt = novo Point ();


// Imprime 0, 0
console . log ( ` $ { pt . x } , $ { pt . y } ` );

Assim como com const , let e var , o inicializador de uma propriedade de classe será usado para inferir seu tipo:

const pt = novo Point ();


pt . x = "0" ;

O
O tipo
tipo 'string'
'string' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo 'número'.
'número'.

--strictPropertyInitialization

https://translate.googleusercontent.com/translate_f 105/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
o A configuração de strictPropertyInitialization controla se os campos de classe precisam ser
inicializado no construtor.

class BadGreeter {
nome : string ;

A
A propriedade
propriedade 'nome'
'nome' não
não tem
tem inicializador
inicializador ee não
não está
é definitivamente
definitivamente
atribuída
atribuída
noem
oconstrutor.
construtor.

class GoodGreeter {
nome : string ;

construtor () {
isso . nome = "olá" ;
}
}

Página 140
Observe que o campo precisa ser inicializado no próprio construtor. TypeScript não analisa
métodos que você invoca do construtor para detectar inicializações, porque uma classe derivada pode
sobrescrever esses métodos e falhar ao inicializar os membros.

Se você pretende inicializar definitivamente um campo por meios diferentes do construtor (por exemplo,
talvez uma biblioteca externa esteja preenchendo parte de sua classe para você), você pode usar a tarefa definitiva
operador de asserção ,! :

class OKGreeter {
// Não inicializado, mas sem erro
nome !: string ;
}

somente leitura

Os campos podem ser prefixados com o modificador somente leitura . Isso evita atribuições ao campo fora
do construtor.

class Greeter {
nome somente leitura : string = "mundo" ;

construtor ( outroNome ?: string ) {


if ( otherName ! == undefined ) {
isso . nome = outroNome ;
}
}

err () {
isso . nome = "não está ok" ;

Não
Não éé possível
possível atribuir
atribuir aa 'nome'
'nome' porque
porque éé uma
uma propriedade
propriedade somente
somente leitura.
leitura.

}
}
const g = novo Greeter ();

https://translate.googleusercontent.com/translate_f 106/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
g . name = "também não está ok" ;

Não
Não éé possível
possível atribuir
atribuir aa 'nome'
'nome' porque
porque éé uma
uma propriedade
propriedade somente
somente leitura.
leitura.

Construtores

Página 141
Os construtores de classes são muito semelhantes às funções. Você pode adicionar Leitura de fundo:

parâmetros com anotações de tipo, valores padrão e sobrecargas: Construtor (MDN)

class Point {
x : número ;
y : número ;

// Assinatura normal com padrões


construtor ( x = 0 , y = 0 ) {
isso . x = x ;
isso . y = y ;
}
}

class Point {
// Overloads
construtor ( x : número , y : string );
construtor ( s : string );
construtor ( xs : any , y ?: any ) {
// TBD
}
}

Existem apenas algumas diferenças entre as assinaturas do construtor de classe e as assinaturas de função:

Os construtores não podem ter parâmetros de tipo - eles pertencem à declaração da classe externa, que
nós aprenderemos mais tarde

Construtores não podem ter anotações de tipo de retorno - o tipo de instância de classe é sempre o que
retornou

Super Chamadas

Assim como no JavaScript, se você tiver uma classe base, precisará chamar super (); em seu construtor
corpo antes de usar qualquer isso. membros:

Página 142

class Base {
k=4;

https://translate.googleusercontent.com/translate_f 107/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
}

class Derived extends Base {


construtor () {
// Imprime um valor errado no ES5; lança exceção no ES6
console . log ( este . k );

'super'
'super' deve
deve ser
ser chamado
chamado antes
antes de
de acessar
acessar 'this'
'this' no
no construtor
construtor de
de um
um
classe
classe derivada.
derivada.

super ();
}
}

Esquecer de chamar super é um erro fácil de cometer em JavaScript, mas o TypeScript dirá quando
é necessário.

Métodos

Uma propriedade de função em uma classe é chamada de método. Métodos podem usar todos
Leitura de fundo:
o mesmo tipo de anotações que funções e construtores:
Definições de método

class Point {
x = 10 ;
y = 10 ;

escala ( n : número ): vazio {


isso . x * = n ;
isso . y * = n ;
}
}

Além das anotações de tipo padrão, o TypeScript não adiciona nada de novo aos métodos.

Observe que dentro de um corpo de método, ainda é obrigatório acessar campos e outros métodos por meio dele . .
Um nome não qualificado em um corpo de método sempre se referirá a algo no escopo envolvente:

Página 143

deixe x : número = 0 ;

classe C {
x : string = "olá" ;

m () {
// Isso está tentando modificar 'x' da linha 1, não a propriedade da classe
x = "mundo" ;

O
O tipo
tipo 'string'
'string' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo 'número'.
'número'.

}
}

Getters / Setters

https://translate.googleusercontent.com/translate_f 108/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
As classes também podem ter acessores:

classe C {
_comprimento = 0 ;
obter comprimento () {
devolva isso . _length ;
}
definir comprimento ( valor ) {
isso . _length = valor ;
}
}

Observe que um par get / set baseado em campo sem lógica extra raramente é útil em JavaScript. Está bem para

exponha campos públicos se você não precisar adicionar lógica adicional durante as operações get / set.

O TypeScript tem algumas regras especiais de inferência para acessadores:

Se get existe, mas não definido , a propriedade é automaticamente somente leitura

Se o tipo do parâmetro setter não for especificado, ele será inferido a partir do tipo de retorno do getter

Getters e setters devem ter a mesma visibilidade de membro

Desde a TypeScript 4.3 , é possível ter acessores com diferentes tipos de obtenção e configuração.

Página 144

classe Thing {
_size = 0 ;

obter tamanho (): número {


devolva isso . _size ;
}

definir tamanho ( valor : string | número | booleano ) {


deixe num = número ( valor );

// Não permite NaN, Infinity, etc

if (! Número . isFinite ( num )) {


isso . _size = 0 ;
retorno ;
}

isso . _size = num ;


}
}

Assinaturas de índice

As classes podem declarar assinaturas de índice; estes funcionam da mesma forma que as assinaturas de índice para outro objeto
tipos :

class MyClass {
[ s : string ]: booleano | (( s : string ) => booleano );

check ( s : string ) {

https://translate.googleusercontent.com/translate_f 109/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
retorna este [ s ] como booleano ;
}
}

Como o tipo de assinatura de índice também precisa capturar os tipos de métodos, não é fácil
usar esses tipos de maneira útil. Geralmente é melhor armazenar dados indexados em outro lugar, em vez de
a própria instância da classe.

Herança de classe

Página 145
Como outras linguagens com recursos orientados a objetos, as classes em JavaScript podem herdar da base
Aulas.

implementa cláusulas

Você pode usar uma implementos cláusula de verificar que uma classe satisfaz uma determinada interface de . Um erro
será emitido se uma classe falhar em implementá-lo corretamente:

interface Pingable {
ping (): vazio ;
}

classe Sonar implementa Pingable {


ping () {
console . log ( "ping!" );
}
}

class Ball implementa Pingable {

A
A classe
classe 'Ball'
'Ball' implementa
implementa incorretamente
incorretamente aa interface
interface 'Pingable'.
'Pingable'.
A
A propriedade
propriedade 'ping'
'ping' está
está ausente
ausente no
no tipo
tipo 'Bola',
'Bola', mas
mas éé necessária
necessária no
no tipo
tipo
'Pingable'.
'Pingable'.

pong () {
console . log ( "pong!" );
}
}

As classes também podem implementar interfaces múltiplas, por exemplo, a classe C implementa A, B { .

Precauções

É importante entender que uma cláusula implements é apenas uma verificação de que a classe pode ser
tratado como o tipo de interface. Isso não muda o tipo da classe ou seus métodos. Um comum
A fonte do erro é assumir que uma cláusula implements mudará o tipo de classe - não muda!

https://translate.googleusercontent.com/translate_f 110/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 146

interface Checkable {
verificar ( nome : string ): booleano ;
}

class NameChecker implementa Checkable {


cheque ( s ) {

'S'
'S' parâmetro
parâmetro tem
tem implicitamente
implicitamente um
um 'qualquer'
'qualquer' tipo.
tipo.

// Não observe nenhum erro aqui


return s . toLowercse () === "ok" ;

algum

}
}

Neste exemplo, nós talvez esperar que s 's tipo seria influenciada pelo nome: string
parâmetro de verificação . Não é - implementos cláusulas não mudar a forma como o corpo da classe está marcada
ou seu tipo inferido.

Da mesma forma, implementar uma interface com uma propriedade opcional não cria essa propriedade:

interface A {
x : número ;
y ?: número ;
}
classe C implementa A {
x=0;
}
const c = novo C ();
c . y = 10 ;

A
A propriedade
propriedade 'y'
'y' não
não existe
existe no
no tipo
tipo 'C'.
'C'.

estende cláusulas

As classes podem estender-se a partir de uma classe base. Uma classe derivada tem todos os
Leitura de fundo:
propriedades e métodos de sua classe base, e também definem
extends keyword (MDN)
membros.

Página 147

class Animal {
mover () {
console . log ( "Seguindo em frente!" );
}
}

class Dog extends Animal {


woof ( vezes : número ) {
para ( seja i = 0 ; i < vezes ; i ++) {
console . log ( "woof!" );
}
}

https://translate.googleusercontent.com/translate_f 111/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
}

const d = novo Cachorro ();


// Método da classe base
d . mover ();
// Método de classe derivada
d . trama ( 3 );

Métodos de substituição

Uma classe derivada também pode substituir um campo ou propriedade da classe base. Você pode
Leitura de fundo:
usar o super. sintaxe para métodos de classe base de acessos. Observe que
superpalavra-chave (MDN)
porque as classes JavaScript são um objeto de pesquisa simples, não há
noção de um "supercampo".

O TypeScript impõe que uma classe derivada seja sempre um subtipo de sua classe base.

Por exemplo, esta é uma maneira legal de substituir um método:

Página 148

class Base {
saudar () {
console . log ( "Olá, mundo!" );
}
}

class Derived extends Base {


saudar ( nome ?: string ) {
if ( nome === indefinido ) {
super . cumprimentar ();
} else {
console . log ( `Olá, $ { name . toUpperCase () } ` );
}
}
}

const d = novo derivado ();


d . cumprimentar ();
d . cumprimentar ( "leitor" );

É importante que uma classe derivada siga seu contrato de classe base. Lembre-se que é muito comum
(e sempre válido!) para se referir a uma instância de classe derivada por meio de uma referência de classe base:

// Alias ​da instância derivada por meio de uma referência de classe base
const b : Base = d ;

https://translate.googleusercontent.com/translate_f 112/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
// Sem problemas
b . cumprimentar ();

E se Derived não seguisse o contrato da Base ?

Página 149

class Base {
saudar () {
console . log ( "Olá, mundo!" );
}
}

class Derived extends Base {


// Tornar este parâmetro obrigatório
saudar ( nome : string ) {

A
A propriedade
propriedade 'saudação'
'saudação' no
no tipo
tipo 'Derivado'
'Derivado' não
não pode
pode ser
ser atribuída
atribuída ao
à mesma
mesmopropriedade
propriedade
no tipo de base
no tipo
'Base'.
base 'Base'.
O
O tipo
tipo '(nome:
'(nome: string)
string) =>
=> void'
void' não
não pode
pode ser
ser atribuído
atribuído ao
ao tipo
tipo '()
'() =>
=> void'.
void'.

console . log ( `Olá, $ { name . toUpperCase () } ` );


}
}

Se compilássemos este código apesar do erro, este exemplo travaria:

const b : Base = novo derivado ();


// Falha porque "nome" será indefinido
b . cumprimentar ();

Ordem de Inicialização

A ordem de inicialização das classes JavaScript pode ser surpreendente em alguns casos. Vamos considerar este código:

https://translate.googleusercontent.com/translate_f 113/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 150

class Base {
nome = "base" ;
construtor () {
console . log ( "Meu nome é" + este . nome );
}
}

class Derived extends Base {


nome = "derivado" ;
}

// Imprime "base", não "derivado"


const d = novo derivado ();

O que aconteceu aqui?

A ordem de inicialização da classe, conforme definida pelo JavaScript, é:

Os campos da classe base são inicializados

O construtor da classe base é executado

Os campos da classe derivada são inicializados

O construtor da classe derivada é executado

Isso significa que o construtor da classe base viu seu próprio valor para nome durante seu próprio construtor,
porque as inicializações do campo da classe derivada ainda não foram executadas.

Herdando tipos integrados

Nota: Se você não planeja herdar de tipos integrados como Array , Error , Map , etc. ou sua compilação

alvo está explicitamente definido como ES6 / ES2015 ou superior, você pode pular esta seção

No ES2015, os construtores que retornam um objeto substituem implicitamente o valor deste por qualquer
chamadores de super (...) . É necessário que o código do construtor gerado capture qualquer potencial
valor de retorno de super (...) e substitua por este .

Como resultado, as subclasses de Error , Array e outros podem não funcionar mais conforme o esperado. Isso é devido ao
o fato de que as funções de construtor para Error , Array e similares usam ECMAScript 6's

new.target para ajustar a cadeia de protótipos; no entanto, não há como garantir um valor para

Página 151
new.target ao invocar um construtor em ECMAScript 5. Outros compiladores de nível inferior geralmente
têm a mesma limitação por padrão.

Para uma subclasse como a seguinte:

class MsgError extends Error {


construtor ( m : string ) {

https://translate.googleusercontent.com/translate_f 114/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
super ( m );
}
dizer olá () {
retornar "olá" + isso . mensagem ;
}
}

você pode descobrir que:

métodos podem ser indefinidos em objetos retornados pela construção dessas subclasses, portanto, chamar

sayHello resultará em um erro.

instanceof será quebrado entre as instâncias da subclasse e suas instâncias, então (novo
MsgError ()) instanceof MsgError retornará false .

Como recomendação, você pode ajustar manualmente o protótipo imediatamente após qualquer super (...)
chamadas.

class MsgError extends Error {


construtor ( m : string ) {
super ( m );

// Defina o protótipo explicitamente.


Objeto . setPrototypeOf ( this , MsgError . prototype );
}

dizer olá () {
retornar "olá" + isso . mensagem ;
}
}

No entanto, qualquer subclasse de MsgError terá que definir manualmente o protótipo também. Para tempos de execução
que não suporta Object.setPrototypeOf, em vez disso, você pode usar __proto__ .

Página 152
Infelizmente, essas soluções alternativas não funcionarão no Internet Explorer 10 e anteriores . Um pode
copiar métodos manualmente do protótipo para a própria instância (ou seja, MsgError.prototype
sobre isso ), mas a própria cadeia de protótipo não pode ser corrigida.

Visibilidade do membro
Você pode usar o TypeScript para controlar se certos métodos ou propriedades são visíveis ao código fora
a classe.

público

A visibilidade padrão dos membros da classe é pública . Um membro público pode ser acessado em qualquer lugar:

class Greeter {
saudação pública () {
console . log ( "oi!" );
}
}
const g = novo Greeter ();
g . cumprimentar ();

https://translate.googleusercontent.com/translate_f 115/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Como public já é o modificador de visibilidade padrão, você nunca precisa escrevê-lo em uma classe
membro, mas pode optar por fazê-lo por motivos de estilo / legibilidade.

protegido

membros protegidos são visíveis apenas para subclasses da classe em que foram declarados.

Página 153

class Greeter {
saudação pública () {
console . log ( "Olá," + this . getName ());
}
protegido getName () {
retornar "oi" ;
}
}

class SpecialGreeter extends Greeter {


public howdy () {
// OK para acessar o membro protegido aqui
console . log ( "Olá," + this . getName ());
}
}
const g = novo SpecialGreeter ();
g . cumprimentar (); // OK
g . getName ();

A
A propriedade
propriedade 'getName'
'getName' éé protegida
protegida ee acessível
acessível apenas
apenas dentro
dentro da
da classe
classe 'Greeter'
'Greeter'
e suas subclasses.
e suas subclasses.

Exposição de membros protegidos

As classes derivadas precisam seguir seus contratos de classe base, mas podem optar por expor um subtipo de
classe base com mais recursos. Isso inclui tornar públicos os membros protegidos :

class Base {
m protegido = 10 ;
}
class Derived extends Base {
// Sem modificador, então o padrão é 'público'
m = 15 ;
}
const d = novo derivado ();

https://translate.googleusercontent.com/translate_f 116/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
console . log ( d . m ); // OK

Observe que Derived já era capaz de ler e escrever livremente m , então isso não altera significativamente
a "segurança" desta situação. A principal coisa a notar aqui é que na classe derivada, precisamos ser

Página 154
cuidado para repetir o modificador protegido se esta exposição não for intencional.

Acesso protegido de hierarquia cruzada

Diferentes idiomas OOP discordam sobre se é legal acessar um membro protegido


por meio de uma referência de classe base:

class Base {
protegido x : número = 1 ;
}
class Derived1 extends Base {
protegido x : número = 5 ;
}
class Derived2 extends Base {
f1 ( outro : Derived2 ) {
outro . x = 10 ;
}
f2 ( outro : Base ) {
outro . x = 10 ;

A
A propriedade
propriedade 'x'
'x' éé protegida
protegida ee acessível
acessível apenas
apenas por
por meio
meio de
de uma
uma instância
instância de
de classe
classe
'Derived2'.
'Derived2'.
Esta é Esta
uma éinstância
uma instância
da classe
da classe
'Base'.'Base'.

}
}

Java, por exemplo, considera isso legal. Por outro lado, C # e C ++ escolheram que este código
deve ser ilegal.

TypeScript está lado a lado com C # e C ++ aqui, porque acessar x em Derived2 só deve ser legal
de Derived2 subclasses 's, e Derived1 não é um deles. Além disso, se acessar x por meio de
uma referência Derived1 é ilegal (o que certamente deveria ser!), então acessá-la por meio de uma base
a referência de classe nunca deve melhorar a situação.

Veja também Por que não consigo acessar um membro protegido de uma classe derivada? o que explica mais de
O raciocínio de C #.

privado

privado é como protegido , mas não permite acesso ao membro mesmo de subclasses:

Página 155

class Base {
privado x = 0 ;

https://translate.googleusercontent.com/translate_f 117/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
}
const b = nova Base ();
// Não é possível acessar de fora da classe
console . log ( b . x );

A
A propriedade
propriedade 'x'
'x' éé privada
privada ee acessível
acessível apenas
apenas dentro
dentro da
da classe
classe 'Base'.
'Base'.

class Derived extends Base {


showX () {
// Não é possível acessar em subclasses
console . log ( este . x );

A
A propriedade
propriedade 'x'
'x' éé privada
privada ee acessível
acessível apenas
apenas dentro
dentro da
da classe
classe 'Base'.
'Base'.

}
}

Como os membros privados não são visíveis para as classes derivadas, uma classe derivada não pode aumentar seu
visibilidade:

class Base {
privado x = 0 ;
}
class Derived extends Base {

A
A classe
classe 'Derivado'
'Derivado' estende
estende incorretamente
incorretamente aa classe
classe base
base 'Base'.
'Base'.
A
A propriedade
propriedade 'x'
'x' éé privada
privada no
no tipo
tipo 'Base',
'Base', mas
mas não
não no
no tipo
tipo 'Derivado'.
'Derivado'.

x=1;
}

Acesso privado entre instâncias

Diferentes linguagens OOP discordam sobre se diferentes instâncias da mesma classe podem acessar
membros privados uns dos outros . Embora linguagens como Java, C #, C ++, Swift e PHP permitam isso,
Ruby não.

Página 156
O TypeScript permite acesso privado entre instâncias :

classe A {
privado x = 10 ;

public sameAs ( other : A ) {


// Sem erro
retornar outro . x === isso . x ;
}
}

Ressalvas

Como outros aspectos do sistema de tipos do TypeScript, privado e protegido só são aplicados durante
verificação de tipo .

https://translate.googleusercontent.com/translate_f 118/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Isso significa que as construções de tempo de execução do JavaScript, como em ou pesquisa de propriedade simples, ainda podem acessar um
membro privado ou protegido :

class MySafe {
secretKey privado = 12345 ;
}

// Em um arquivo JavaScript ...


const s = novo MySafe ();
// imprimirá 12345
console . log ( s . secretKey );

privado também permite o acesso usando a notação de colchetes durante a verificação de tipo. Isso torna privado -
campos declarados potencialmente mais fáceis de acessar para coisas como testes de unidade, com a desvantagem de que estes
os campos são soft private e não impõem estritamente a privacidade.

Página 157

class MySafe {
secretKey privado = 12345 ;
}

const s = novo MySafe ();

// Não permitido durante a verificação de tipo


console . log ( s . secretKey );

Propriedade
A propriedade
'secretKey'
'secretKey'
é privado
é privada
e apenas
e acessível
acessível
apenas
dentro
dentro
da da
classe
classe 'MySafe'.
'MySafe'.

// OK
console . log ( s [ "chave secreta" ]);

Ao contrário do privado do TypeScripts , o do JavaScriptcampos privados ( # ) permanecem privados após a compilação e


não forneça as escotilhas de escape mencionadas anteriormente, como acesso à notação de colchetes, tornando-as
difícil privado.

class Dog {
#barkAmount = 0 ;
personalidade = "feliz" ;

construtor () {}
}

"use estrito" ;
class Dog {
https://translate.googleusercontent.com/translate_f 119/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

#barkAmount = 0 ;
personalidade = "feliz" ;
construtor () {}
}

Ao compilar para ES2021 ou menos, o TypeScript usará WeakMaps no lugar de # .

Página 158

"use estrito" ;
var _Dog_barkAmount ;
class Dog {
construtor () {
_Dog_barkAmount . definir ( este , 0 );
isso . personalidade = "feliz" ;
}
}
_Dog_barkAmount = novo WeakMap ();

Se você precisa proteger valores em sua classe de agentes mal-intencionados, você deve usar mecanismos que
oferecem privacidade de tempo de execução difícil, como encerramentos, WeakMaps ou campos privados. Observe que estes adicionaram
verificações de privacidade durante o tempo de execução podem afetar o desempenho.

Membros estáticos
As classes podem ter membros estáticos . Esses membros não são
Leitura de fundo:
associada com um caso particular da classe. Eles podem ser
Membros estáticos (MDN)
acessada através do próprio objeto construtor da classe:

class MyClass {
estático x = 0 ;
static printX () {
console . log ( MyClass . x );
}
}
console . log ( MyClass . x );
MyClass . printX ();

Membros estáticos também podem usar os mesmos modificadores de visibilidade público , protegido e privado :

class MyClass {
estático privado x = 0 ;
}
console . log ( MyClass . x );

A
A propriedade
propriedade 'x'
'x' éé privada
privada ee acessível
acessível apenas
apenas dentro
dentro da
da classe
classe 'MyClass'.
'MyClass'.

https://translate.googleusercontent.com/translate_f 120/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Página 159
Membros estáticos também são herdados:

class Base {
static getGreeting () {
return "Olá, mundo" ;
}
}
class Derived extends Base {
myGreeting = Derivado . getGreeting ();
}

Nomes estáticos especiais

Geralmente não é seguro / possível sobrescrever propriedades do protótipo de Função . Porque


aulas são próprias funções que podem ser invocadas com novas certos, estáticos nomes não podem ser
usado. Propriedades de função como nome , comprimento e chamada não são válidas para definir como estáticas
membros:

classe S {
nome estático = "S!" ;

A
A propriedade
propriedade estática
estática 'name'
'nome' está
está em
em conflito
conflito com
com aa propriedade
propriedade interna
interna 'Function.name'
'Function.name' de
da
função
função
construtora
construtora
'S'.'S'.

Por que não há classes estáticas?

TypeScript (e JavaScript) não tem uma construção chamada classe estática da mesma forma que C # e
Java faz.

Essas construções só existem porque essas linguagens forçam todos os dados e funções a estarem dentro de um
classe; porque essa restrição não existe no texto datilografado, não há nenhuma necessidade para eles. Uma classe com apenas
uma única instância é normalmente representada apenas como um objeto normal em JavaScript / TypeScript.

Por exemplo, não precisamos de uma sintaxe de "classe estática" no TypeScript porque um objeto regular (ou mesmo
função de nível superior) fará o trabalho tão bem:

Página 160

// desnecessária classe "estático"


class MyStaticClass {
static doSomething () {}
}

// Preferido (alternativa 1)
function doSomething () {}

// Preferido (alternativa 2)
const MyHelperObject = {
dosomething () {},
};

https://translate.googleusercontent.com/translate_f 121/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

blocos estáticos em classes


Os blocos estáticos permitem que você escreva uma sequência de instruções com seu próprio escopo que pode acessar
campos privados dentro da classe contida. Isso significa que podemos escrever código de inicialização com todos os
capacidades de escrever instruções, sem vazamento de variáveis ​e acesso total aos internos de nossa classe.

class Foo {
static #count = 0 ;

obter contagem () {
retornar Foo . #count ;
}

static {
tente {
const lastInstances = loadLastInstances ();
Foo . #count + = lastInstances . comprimento ;
}
pegar {}
}
}

Classes Genéricas
As classes, assim como as interfaces, podem ser genéricas. Quando uma classe genérica é instanciado com nova , seu tipo
parâmetros são inferidas da mesma forma que em uma chamada de função:

Página 161

class Box < Type > {


conteúdo : Tipo ;
construtor ( valor : Type ) {
isso . conteúdo = valor ;
}
}

const b = new Box ( "olá!" );

const b: Box <string>

As classes podem usar restrições e padrões genéricos da mesma forma que as interfaces.

Parâmetros de tipo em membros estáticos

Este código não é legal e pode não ser óbvio por que:

class Box < Type > {


static defaultValue : Type ;

Membros
Membros estáticos
estáticos não
não podem
podem fazer
fazer referência
referência aa parâmetros
parâmetros de
de tipo
tipo de
de classe.
classe.

https://translate.googleusercontent.com/translate_f 122/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Lembre-se de que os tipos são sempre totalmente apagados! Em tempo de execução, há apenas um Box.defaultValue
slot de propriedade. Isso significa que definir Box <string> .defaultValue (se isso fosse possível)
também altere Box <number> .defaultValue - não é bom. Os membros estáticos de uma classe genérica
nunca pode se referir aos parâmetros de tipo da classe.

isso em Runtime in Classes


É importante lembrar que o TypeScript não muda o tempo de execução
Leitura de fundo:
comportamento do JavaScript, e esse JavaScript é um tanto famoso por
esta palavra-chave (MDN)
tendo alguns comportamentos de tempo de execução peculiares.

O manuseio do JavaScript para isso é realmente incomum:

Página 162

class MyClass {
nome = "MinhaClasse" ;
getName () {
devolva isso . nome ;
}
}
const c = new MyClass ();
const obj = {
nome: "obj" ,
getName: c . getName ,
};

// Imprime "obj", não "MyClass"


console . log ( obj . getName ());

Resumindo, por padrão, o valor disso dentro de uma função depende de como a função era
chamado. Neste exemplo, porque a função foi chamado através do obj referência, o seu valor de

isso era obj, e não a instância da classe.

Isso raramente é o que você deseja que aconteça! O TypeScript fornece algumas maneiras de mitigar ou prevenir isso
tipo de erro.

Funções de seta

Se você tem uma função que costuma ser chamada de uma forma que perde seu
Leitura de fundo:
neste contexto, pode fazer sentido usar uma propriedade de função de seta
Funções de seta (MDN)
em vez de uma definição de método:

class MyClass {
nome = "MinhaClasse" ;
getName = () => {
devolva isso . nome ;
};
}
const c = new MyClass ();
const g = c . getName ;
// Imprime "MyClass" em vez de travar
console . log ( g ());

https://translate.googleusercontent.com/translate_f 123/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 163
Isso tem algumas desvantagens:

A este valor é garantido para ser correto em tempo de execução, mesmo para código não verificado com
TypeScript

Isso vai usar mais memória, porque cada instância de classe terá sua própria cópia de cada função
definido desta forma

Você não pode usar super.getName em uma classe derivada, porque não há nenhuma entrada na cadeia de protótipo
para buscar o método da classe base de

estes parâmetros

Em uma definição de método ou função, um parâmetro inicial denominado this tem um significado especial em
TypeScript. Esses parâmetros são apagados durante a compilação:

// Entrada do TypeScript com o parâmetro 'este'


function fn ( this : SomeType , x : number ) {
/ * ... * /
}

// JavaScript output
função fn ( x ) {
/ * ... * /
}

O TypeScript verifica se a chamada de uma função com este parâmetro é feita com um contexto correto.
Em vez de usar uma função de seta, podemos adicionar um parâmetro this para definições de método para
impor estaticamente que o método seja chamado corretamente:

Página 164

class MyClass {
nome = "MinhaClasse" ;
getName ( isto : MyClass ) {
devolva isso . nome ;
}
}
const c = new MyClass ();
// OK

https://translate.googleusercontent.com/translate_f 124/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
c . getName ();

// Erro, iria travar


const g = c . getName ;
console . log ( g ());

O
O contexto
contexto 'this'
'this' do
do tipo
tipo 'void'
'void' não
não pode
é atribuível
ser atribuído
ao 'this'aodo
'this'
método
do método
do
digite
tipo'MyClass'.
'MyClass'.

Este método faz as compensações opostas da abordagem da função seta:

Os chamadores de JavaScript ainda podem usar o método de classe incorretamente sem perceber

Apenas uma função por definição de classe é alocada, ao invés de uma por instância de classe

As definições do método base ainda podem ser chamadas por meio de super .

estes tipos
Nas classes, um tipo especial denominado this refere - se dinamicamente ao tipo da classe atual. Vamos ver
como isso é útil:

class Box {
conteúdo : string = "" ;
set ( valor : string ) {

(método) Box.set (valor: string): este

isso . conteúdo = valor ;


devolva isso ;
}
}

Página 165
Aqui, o TypeScript inferiu o tipo de retorno do conjunto como sendo este , em vez de Box . Agora vamos fazer um
subclasse de Box :

class ClearableBox extends Box {


limpar () {
isso . conteúdo = "" ;
}
}

const a = new ClearableBox ();


const b = a . set ( "olá" );

const b: ClearableBox

Você também pode usar isso em uma anotação de tipo de parâmetro:

class Box {
conteúdo : string = "" ;
sameAs ( other : this ) {
retornar outro . conteúdo === isso . conteúdo ;

https://translate.googleusercontent.com/translate_f 125/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
}
}

Isso é diferente de escrever outro: Box - se você tiver uma classe derivada, seu método sameAs irá
agora aceite apenas outras instâncias da mesma classe derivada:

Página 166

class Box {
conteúdo : string = "" ;
sameAs ( other : this ) {
retornar outro . conteúdo === isso . conteúdo ;
}
}

class DerivedBox extends Box {


otherContent : string = "?" ;
}

base const = nova caixa ();


const derivado = novo DerivedBox ();
derivado . sameAs ( base );

O
O argumento
argumento do
do tipo
tipo 'Box'
'Box' não
não pode
pode ser
ser atribuído
atribuído ao
ao parâmetro
parâmetro do
do tipo
tipo
'DerivedBox'.
'DerivedBox'.
A
A propriedade
propriedade 'otherContent'
'otherContent' está
está ausente
ausente no
no tipo
tipo 'Box',
'Box', mas
mas éé obrigatória
obrigatória no
no tipo
tipo
'DerivedBox'.
'DerivedBox'.

este tipo de guardas com base

Você pode usar este é Type na posição de retorno para métodos em classes e interfaces. Quando
misturado com um estreitamento de tipo (por exemplo, declarações if ), o tipo do objeto de destino seria estreitado
para o tipo especificado .

https://translate.googleusercontent.com/translate_f 126/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 167

class FileSystemObject {
isFile (): este é FileRep {
retornar esta instância de FileRep ;
}
isDirectory (): este é o Directory {
retornar esta instância do Directory ;
}
isNetworked (): esta é a rede e esta {
devolva isso . em rede ;
}
construtor ( caminho público : string , rede privada : booleano ) {}
}

class FileRep extends FileSystemObject {


construtor ( caminho : string , conteúdo público : string ) {
super ( caminho , falso );
}
}

class Directory extends FileSystemObject {


filhos : FileSystemObject [];
}

interface em rede {
host : string ;
}

const fso : FileSystemObject = new FileRep ( "foo / bar.txt" , "foo" );

se ( FSO . isFile ()) {


fso . conteúdo ;

const fso: FileRep

} Else if ( FSO . IsDirectory ()) {


fso . crianças ;

const fso: Directory

} Else if ( FSO . IsNetworked ()) {


fso . hospedeiro ;

const fso: Networked & FileSystemObject

Página 168

Um caso de uso comum para um protetor de tipo baseado neste é permitir a validação preguiçosa de um campo específico.
Por exemplo, este caso remove um undefined do valor mantido dentro da caixa quando hasValue
https://translate.googleusercontent.com/translate_f 127/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

foi verificado como verdadeiro:

class Box < T > {


valor ?: T ;

hasValue (): este é {value: T } {


devolva isso . valor ! == indefinido ;
}
}

caixa const = nova caixa ();


caixa . valor = "Gameboy" ;

caixa . valor ;

(propriedade) Caixa <desconhecido> .valor ?: desconhecido

if ( box . hasValue ()) {


caixa . valor ;

valor (propriedade): desconhecido

Propriedades de Parâmetro
TypeScript oferece sintaxe especial para transformar um parâmetro de construtor em uma propriedade de classe com o
mesmo nome e valor. Eles são chamados de propriedades de parâmetro e são criados prefixando um
argumento do construtor com um dos modificadores de visibilidade public , private , protected ou

somente leitura . O campo resultante obtém esse (s) modificador (es):

Página 169

class Params {
construtor (
público somente leitura x : número ,
protegido y : número ,
z privado : número
){
// Nenhum corpo necessário
}
}
const a = novos Params ( 1 , 2 , 3 );
console . log ( a . x );

(propriedade) Params.x: número

console . log ( a . z );

A
A propriedade
propriedade 'z'
'z' éé privada
privada ee acessível
acessível apenas
apenas dentro
dentro da
da classe
classe 'Params'.
'Params'.

https://translate.googleusercontent.com/translate_f 128/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Expressões de classe
As expressões de classe são muito semelhantes às declarações de classe. O único
Leitura de fundo:
a diferença real é que as expressões de classe não precisam de um nome, embora
Expressões de classe (MDN)
podemos nos referir a eles por meio de qualquer identificador que eles acabaram vinculando
para:

const someClass = class < Type > {


conteúdo : Tipo ;
construtor ( valor : Type ) {
isso . conteúdo = valor ;
}
};

const m = new someClass ( "Olá, mundo" );

const m: someClass <string>

Classes e membros abstratos

Página 170
Classes, métodos e campos no TypeScript podem ser abstratos.

Um método abstrato ou campo abstrato é aquele que não teve uma implementação fornecida. Esses
os membros devem existir dentro de uma classe abstrata, que não pode ser instanciada diretamente.

O papel das classes abstratas é servir como uma classe base para as subclasses que implementam todos os
membros abstratos. Quando uma classe não possui nenhum membro abstrato, ela é considerada concreta.

Vejamos um exemplo:

classe abstrata Base {


getName abstrato (): string ;

printName () {
console . log ( "Olá," + this . getName ());
}
}

const b = nova Base ();

Não
Não éé possível
possível criar
criar uma
uma instância
instância de
de uma
uma classe
classe abstrata.
abstrata.

Não podemos instanciar o Base com new porque é abstrato. Em vez disso, precisamos fazer uma classe derivada
e implementar os membros abstratos:

class Derived extends Base {


getName () {
retornar "mundo" ;
}
}

https://translate.googleusercontent.com/translate_f 129/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
const d = novo derivado ();
d . printName ();

Observe que se esquecermos de implementar os membros abstratos da classe base, obteremos um erro:

Página 171

class Derived extends Base {

Classe
Classe não
não abstrata
abstrata 'Derivada'
'Derivada' não
não implementa
implementa resumo
membroherdado
abstrato herdado
membro
'getName'
'getName'
da classeda
'Base'.
classe 'Base'.

// esqueci de fazer qualquer coisa


}

Assinaturas de construção abstrata

Às vezes você deseja aceitar alguma função construtora de classe que produz uma instância de uma classe
que deriva de alguma classe abstrata.

Por exemplo, você pode querer escrever este código:

function greet ( ctor : typeof Base ) {


instância const = novo ctor ();

Não
Não éé possível
possível criar
criar uma
uma instância
instância de
de uma
uma classe
classe abstrata.
abstrata.

instância . printName ();


}

O TypeScript está informando corretamente que você está tentando instanciar uma classe abstrata. Afinal, dado
a definição de saudação , é perfeitamente legal escrever este código, o que acabaria por construir um
classe abstrata:

// Mau!
saudar ( Base );

Em vez disso, você deseja escrever uma função que aceite algo com uma assinatura de construção:

https://translate.googleusercontent.com/translate_f 130/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Página 172

função saudação ( ctor : new () => Base ) {


instância const = novo ctor ();
instância . printName ();
}
cumprimentar ( derivado );
saudar ( Base );

O
O argumento
argumento do
do tipo
tipo 'typeof
'typeof Base'
Base' não
não éé atribuível
atribuível ao
ao parâmetro
parâmetro do
do tipo
tipo 'novo
'new
() =>()Base
=> Base'.
'.
Não
Não éé possível
possível atribuir
atribuir um
um tipo
tipo de
de construtor
construtor abstrato
abstrato aa um
um não
construtor
abstratonão abstrato
tipo
modelo.
de construtor.

Agora o TypeScript informa corretamente sobre quais funções de construtor de classe podem ser chamadas -
Derivado pode porque é concreto, mas Base não pode.

Relações Entre Classes


Na maioria dos casos, as classes no TypeScript são comparadas estruturalmente, da mesma forma que outros tipos.

Por exemplo, essas duas classes podem ser usadas no lugar uma da outra porque são idênticas:

class Point1 {
x=0;
y=0;
}

class Point2 {
x=0;
y=0;
}

// OK
const p : Ponto1 = novo Ponto2 ();

Da mesma forma, as relações de subtipo entre as classes existem mesmo se não houver herança explícita:

Página 173

class Person {
nome : string ;
idade : número ;
}

class Employee {
nome : string ;
idade : número ;
salário : número ;
}

// OK
const p : Pessoa = novo funcionário ();

https://translate.googleusercontent.com/translate_f 131/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Isso parece simples, mas existem alguns casos que parecem mais estranhos do que outros.

As classes vazias não têm membros. Em um sistema de tipo estrutural, um tipo sem membros é geralmente um
supertipo de qualquer outra coisa. Então, se você escrever uma classe vazia (não!), Qualquer coisa pode ser usada no lugar de
isto:

classe vazia {}

função fn ( x : vazio ) {
// não posso fazer nada com 'x', então não vou
}

// Tudo bem!
fn ( janela );
fn ({});
fn ( fn );

Página 174

Módulos

JavaScript tem uma longa história de maneiras diferentes de lidar com a modularização de código. TypeScript tendo sido
ao redor desde 2012, implementou suporte para muitos desses formatos, mas com o tempo o
comunidade e a especificação JavaScript convergiram em um formato chamado Módulos ES (ou ES6
módulos). Você pode conhecê-lo como a sintaxe de importação / exportação .

Módulos ES foram adicionados à especificação JavaScript em 2015, e em 2020 tinha amplo suporte na maioria da web
navegadores e tempos de execução de JavaScript.

Para enfocar, o manual cobrirá os Módulos ES e seu popular pré-cursor CommonJS


module.exports = syntax, e você pode encontrar informações sobre os outros padrões de módulo no
seção de referência sob Módulos .

Como os módulos JavaScript são definidos


No TypeScript, assim como no ECMAScript 2015, qualquer arquivo contendo uma importação ou exportação de nível superior é
considerado um módulo.

Por outro lado, um arquivo sem nenhuma declaração de importação ou exportação de nível superior é tratado como um script cujo
os conteúdos estão disponíveis no âmbito global (e, portanto, também para os módulos).

Os módulos são executados em seu próprio escopo, não no escopo global. Isso significa que as variáveis,
funções, classes, etc. declaradas em um módulo não são visíveis fora do módulo, a menos que sejam
exportado explicitamente usando um dos formulários de exportação. Por outro lado, para consumir uma variável, função, classe,
interface, etc. exportado de um módulo diferente, deve ser importado usando um dos import

https://translate.googleusercontent.com/translate_f 132/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
formulários.

Não-módulos
Antes de começar, é importante entender o que o TypeScript considera um módulo. O JavaScript
especificação declara que qualquer arquivo JavaScript sem exportação ou espera de nível superior deve ser
considerado um script e não um módulo.

Dentro de um arquivo de script, as variáveis ​e os tipos são declarados como estando no escopo global compartilhado, e é
assumiu que você usará o opção de compilador outFile para juntar vários arquivos de entrada em um
arquivo de saída ou use várias tags <script> em seu HTML para carregar esses arquivos (na ordem correta!).

Se você tiver um arquivo que atualmente não possui nenhuma importação ou exportação , mas deseja ser tratado
como um módulo, adicione a linha:

Página 175

export {};

o que mudará o arquivo para um módulo que não exporta nada. Esta sintaxe funciona independentemente do seu
alvo do módulo.

Módulos em TypeScript
Existem três coisas principais a considerar ao escrever o módulo -
Leitura Adicional:
código baseado em TypeScript:
JS impaciente (módulos)

MDN: Módulos JavaScript


Sintaxe : qual sintaxe desejo usar para importar e exportar
coisas?

Resolução do Módulo : Qual é a relação entre os nomes dos módulos (ou caminhos) e os arquivos em
disco?

Destino de saída do módulo : como deve ser o meu módulo JavaScript emitido?

Sintaxe do Módulo ES

Um arquivo pode declarar uma exportação principal via padrão de exportação :

// @filename: hello.ts
função padrão de exportação helloWorld () {
console . log ( "Olá, mundo!" );
}

Em seguida, ele é importado por meio de:

importar olá de "./hello.js" ;


olá ();

Além da exportação padrão, você pode ter mais de uma exportação de variáveis ​e funções via
a exportação omitindo o padrão :

https://translate.googleusercontent.com/translate_f 133/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Página 176

// @filename: maths.ts
export var pi = 3,14 ;
exportar deixe squareTwo = 1,41 ;
exportar const phi = 1,61 ;

exportar classe RandomNumberGenerator {}

função de exportação absoluta ( num : número ) {


if ( num < 0 ) retorna num * - 1 ;
return num ;
}

Eles podem ser usados ​em outro arquivo por meio da sintaxe de importação :

importar { pi , phi , absoluto } de "./maths.js" ;

console . log ( pi );
const absPhi = absoluto ( phi );

const absPhi: number

Sintaxe de importação adicional

Uma importação pode ser renomeada usando um formato como import {old as new} :

importar { pi como à € } de "./maths.js" ;

console . log ( Ã € );

(alias) var ¬: número


importar à €

Você pode misturar e combinar a sintaxe acima em uma única importação :

Página 177

// @filename: maths.ts
export const pi = 3,14 ;
exportar classe padrão RandomNumberGenerator {}

// @filename: app.ts
importar RNGen , { pi como à € } de "./maths.js" ;

RNGen ;

https://translate.googleusercontent.com/translate_f 134/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
(alias) classe RNGen
importar RNGen

console . log ( Ã € );

(alias) const ¬: 3,14


importar à €

Você pode pegar todos os objetos exportados e colocá-los em um único namespace usando * como nome :

// @filename: app.ts
import * as math from "./maths.js" ;

console . log ( matemática . pi );


const positivoPhi = matemática . absoluto ( matemática . phi );

const PositivePhi: number

Você pode importar um arquivo e não incluir nenhuma variável em seu módulo atual via importação

"./file" :

// @filename: app.ts
import "./maths.js" ;

console . log ( "3,14" );

Página 178
Nesse caso, a importação não faz nada. No entanto, todo o código em maths.ts foi avaliado, o que
pode desencadear efeitos colaterais que afetam outros objetos.

Sintaxe do módulo ES específico de TypeScript

Os tipos podem ser exportados e importados usando a mesma sintaxe dos valores JavaScript:

// @filename: animal.ts
tipo de exportação Cat = { raça : string ; yearOfBirth : número };

interface de exportação Dog {


raças : string [];
yearOfBirth : número ;
}

// @filename: app.ts
import { Cat , Dog } de "./animal.js" ;
tipo Animais = Gato | Dog ;

O TypeScript estendeu a sintaxe de importação com dois conceitos para declarar uma importação de um tipo:

tipo de importação

https://translate.googleusercontent.com/translate_f 135/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

Que é uma instrução de importação que só pode importar tipos:

// @filename: animal.ts
tipo de exportação Cat = { raça : string ; yearOfBirth : número };

'createCatName'
'createCatName' não
não pode
pode ser
ser usado
usado como
como um
um valor
valor porque
porque foi
foi importado
importado usando
usando
'tipo
'tipo de
de importação'.
importação'.

tipo de exportação Dog = { raças : string []; yearOfBirth : número };


export const createCatName = () => "fofo" ;

// @filename: valid.ts
import tipo { Cat , Dog } de "./animal.js" ;
tipo de exportação Animais = Gato | Dog ;

// @filename: app.ts
importar o tipo { createCatName } de "./animal.js" ;
nome const = createCatName ();

Página 179
Importações de tipo inline

TypeScript 4.5 também permite que importações individuais sejam prefixadas com tipo para indicar que o
a referência importada é um tipo:

// @filename: app.ts
import { createCatName , type Cat , type Dog } de "./animal.js" ;

tipo de exportação Animais = Gato | Dog ;


nome const = createCatName ();

Juntos, eles permitem que um transpiler não TypeScript como Babel, swc ou esbuild saiba o que importa
pode ser removido com segurança.

Sintaxe do módulo ES com comportamento CommonJS

TypeScript tem sintaxe de módulo ES que se correlaciona diretamente a um CommonJS e AMD requerem .
As importações que usam o Módulo ES são, na maioria dos casos, as mesmas que exigem desses ambientes,
mas essa sintaxe garante que você tenha uma correspondência de 1 para 1 em seu arquivo TypeScript com a saída CommonJS:

importar fs = require ( "fs" );


código const = fs . readFileSync ( "hello.ts" , "utf8" );

Você pode aprender mais sobre essa sintaxe no página de referência de módulos.

Sintaxe CommonJS
CommonJS é o formato em que a maioria dos módulos do npm são entregues. Mesmo se você estiver escrevendo
usando a sintaxe dos Módulos ES acima, tendo um breve entendimento de como a sintaxe CommonJS funciona
irá ajudá-lo a depurar mais facilmente.

Exportador

https://translate.googleusercontent.com/translate_f 136/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
Os identificadores são exportados por meio da definição da propriedade exports em um módulo chamado global .

Página 180

função absoluta ( num : número ) {


if ( num < 0 ) retorna num * - 1 ;
return num ;
}

módulo . exportações = {
pi: 3,14 ,
squareTwo: 1,41 ,
phi: 1,61 ,
absoluto ,
};

Então, esses arquivos podem ser importados por meio de uma declaração de requerimento :

const maths = require ( "maths" );


matemática . pi ;

algum

Ou você pode simplificar um pouco usando o recurso de desestruturação em JavaScript:

const { squareTwo } = requer ( "matemática" );


squareTwo ;

const squareTwo: any

Interop de módulos CommonJS e ES

Há uma incompatibilidade de recursos entre os Módulos CommonJS e ES em relação à distinção


entre uma importação padrão e uma importação de objeto de namespace do módulo. TypeScript tem um sinalizador de compilador para
reduzir o atrito entre os dois conjuntos diferentes de restrições com esModuleInterop .

Opções de resolução de módulo do TypeScript

Página 181
A resolução do módulo é o processo de pegar uma string da declaração import ou require , e
determinar a qual arquivo essa string se refere.

O TypeScript inclui duas estratégias de resolução: Classic e Node. Clássico, o padrão quando o
opção de compilador módulo não é comum , está incluído para compatibilidade com versões anteriores. O nó

https://translate.googleusercontent.com/translate_f 137/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…
estratégia replica como o Node.js funciona no modo CommonJS, com verificações adicionais para .ts e

.d.ts .

Existem muitos sinalizadores TSConfig que influenciam a estratégia do módulo no TypeScript:


moduleResolution, baseUrl, caminhos ,rootDirs.

Para obter os detalhes completos sobre como essas estratégias funcionam, você pode consultar o Módulo Resolução.

Opções de saída do módulo do TypeScript


Existem duas opções que afetam a saída JavaScript emitida:

alvo que determina quais recursos JS são reduzidos (convertidos para rodar em versões mais antigas
Tempos de execução do JavaScript) e que são deixados intactos

módulo que determina qual código é usado para os módulos interagirem uns com os outros

Que o destino que você usa é determinado pelos recursos disponíveis no tempo de execução do JavaScript que você
espere executar o código TypeScript. Pode ser: o navegador mais antigo que você suporta, o mais baixo
versão do Node.js que você espera executar ou pode vir de restrições exclusivas do seu tempo de execução -
como Electron, por exemplo.

Toda a comunicação entre os módulos acontece por meio de um carregador de módulo, a opção do compilador módulo
determina qual é usado. Em tempo de execução, o carregador de módulo é responsável por localizar e
executar todas as dependências de um módulo antes de executá-lo.

Por exemplo, aqui está um arquivo TypeScript usando sintaxe de Módulos ES, mostrando algumas opções diferentes
para módulo:

importar { valueOfPi } de "./constants.js" ;

exportar const twoPi = valueOfPi * 2 ;

ES2020

Página 182

importar { valueOfPi } de "./constants.js" ;


exportar const twoPi = valueOfPi * 2 ;

CommonJS

"use estrito" ;
Objeto . defineProperty ( exportações , "__esModule" , { valor: verdadeiro });
exportações . twoPi = vazio 0 ;
const constants_js_1 = require ( "./constants.js" );
exportações . twoPi = constantes_js_1 . valorOfPi * 2 ;

UMD

https://translate.googleusercontent.com/translate_f 138/139
15/11/21, 17:03 Esta cópia do manual do TypeScript foi criada na segunda-feira, 15 de novembro de 2021 contra commit f2fdc3 com TypeScri…

( função ( fábrica ) {
if ( módulo typeof === "objeto" && módulo typeof . exportações === "objeto" )
var v = fábrica ( requer , exportações );
módulo if ( v ! == undefined ) . exportações = v ;
}
else if ( typeof define === "function" && define . amd ) {
define ([ "requer" , "exportações" , "./constants.js" ], fábrica );
}
}) ( função ( requer , exportações ) {
"use estrito" ;
Objeto . defineProperty ( exportações , "__esModule" , { valor: verdadeiro });
exportações . twoPi = vazio 0 ;
const constants_js_1 = require ( "./constants.js" );
exportações . twoPi = constantes_js_1 . valorOfPi * 2 ;
});

Observe que ES2020 é efetivamente igual ao index.ts original .

Você pode ver todas as opções disponíveis e como seu código JavaScript emitido se parece no
Referência TSConfig para módulo.

Página 183

Namespaces TypeScript
TypeScript tem seu próprio formato de módulo chamado namespaces que é anterior aos Módulos ES
padrão. Esta sintaxe tem muitos recursos úteis para a criação de arquivos de definição complexos e ainda vê
uso ativo em DefinitelyTyped. Embora não esteja obsoleto, a maioria dos recursos em namespaces existe
em Módulos ES e recomendamos que você use isso para se alinhar com a direção do JavaScript. Você pode aprender
mais sobre namespaces em a página de referência de namespaces .

https://translate.googleusercontent.com/translate_f 139/139

Você também pode gostar