Você está na página 1de 85

TypeScript: O guia de nitivo

Um guia completo para sua jornada TypeScript

Eduardo Rabelo Follow


Nov 23, 2018 · 40 min read

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Este artigo descreve os recursos e funcionalidades até o TypeScript 3.1.

Uma das linguagens mais interessantes para o desenvolvimento de


aplicativos em larga escala é o TypeScript, da Microsoft . O TypeScript é
único porque é um superconjunto de JavaScript (ES2015+), mas com tipos,
interfaces, tipos genéricos e muito mais. Ao contrário de outras linguagens
que compilam para JavaScript, o TypeScript não tenta alterar o JavaScript
para uma nova linguagem. Ao invés disso, a equipe do TypeScript toma um
cuidado extra para alinhar os recursos de uma maneira bem próxima ao
JavaScript e suas funcionalidades futuras. Devido a isso, os desenvolvedores
que utilizam TypeScript podem aproveitar os recursos mais recentes da
linguagem JavaScript, além de um sistema de tipagem forte para escrever

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
códigos mais organizados, aproveitando as ferramentas avançadas que o
uso de uma linguagem de tipo estaticamente fornece.

O poder real no TypeScript vem de suas ferramentas. Os tipos são um meio


de levar ferramentas de classe mundial à linguagem JavaScript, o que
permite projetos melhores estruturados e mais fáceis de manter. Isso é
especialmente importante à medida que os projetos JavaScript aumentam
de tamanho (seja em linhas de código ou desenvolvedores no projeto). Ter
uma conclusão rápida e precisa, recursos de refatoração e feedback
imediato faz do TypeScript a linguagem ideal para JavaScript em grande
escala. O TypeScript também simpli ca seu uso para quem quer iniciar com
a linguagem! Como o JavaScript é efetivamente o TypeScript sem anotações
de tipo, todas ou partes de um projeto existente podem ser convertidas
imediatamente e, em seguida, podemos aproveitar lentamente tudo o que o
TypeScript tem a oferecer ao longo do tempo.

Embora a documentação do TypeScript tenha melhorado signi cativamente


desde que este guia foi publicado, este guia ainda fornece uma das melhores
visões gerais dos principais recursos do TypeScript, supondo que você já
tenha um conhecimento razoável de JavaScript e um entendimento básico

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
de como funciona a herança baseada em classe (como em Java, PHP, C #,
etc.). O guia é atualizado regularmente para fornecer novas informações
sobre as versões mais recentes do TypeScript.

Índice
Instalação e uso

Con guração

Utilizando let e const

Importação e exportação

Açucares de linguagem

Desestruturação

Outros recursos da linguagem

Tipos

Tipos de Objeto

Tipo “object” em TS 2.2+

Tipos de Tupla

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Tipos de Função

Funções sobrecarregadas

Tipos rigorosos para Funções em TS 2.6+

Tipos Genéricos

Tipos de União

Tipos de Intersecção

Tipando o valor de “this”

Tipos Mapeados em TS 2.1+

Tipos “Mapped”, “Partial”, “Readonly”, “Record” e “Pick” em TS 2.1+

Tipos Condicionais em TS 2.8+

Guardas de Tipo

Classes

Mixins e Herança múltipla

Enumeráveis

Aliases

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Declarações de Ambiente

Carregador de Plugins

Análise de controle de uxo

Instalação e uso
A instalação do TypeScript é tão simples quanto a execução npm install
typescript. Uma vez instalado, o compilador TypeScript estará disponível
executando tsc ou executando uma tarefa local para compilar
automaticamente após cada arquivo ser salvo. Se você quiser experimentar
o TypeScript em seu navegador, o TypeScript Playground permite que você
experimente o TypeScript com um editor de código completo, com a
limitação de que os módulos não podem ser usados. A maioria dos
exemplos deste guia pode ser colado diretamente no playground para ver
rapidamente como o TypeScript é compilado em JavaScript com uma fácil
leitura.

Con guração
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O compilador TypeScript é altamente con gurável, permitindo que o
usuário de na onde os arquivos de origem estão e como eles devem ser
transformados, indo até como podemos con gurar quão restrito o
veri cador de tipos deve ser e se deve permitir arquivos JavaScript. Cada
uma das opções de con guração pode ser passada para o comando tsc, ou
um arquivo tscon g.json pode armazenar as con gurações de um projeto,
de nindo como o compilador deve ser executado toda vez. O tscon g.json
armazena informações sobre vários sinalizadores e con gurações do
compilador, bem como informações de resolução do caminho do módulo.
Uma lista completa de opções do compilador está disponível na
documentação o cial. Um exemplo de tscon g.json do projeto Dojo:

{
"version": "2.1.5",
"compilerOptions": {
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "umd",
"moduleResolution": "node",
"outDir": "_build/",
"removeComments": false,
"sourceMap": true,
"strict": true,
"target": "es5",

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
"lib": ["es2015", "dom"]
},
"include": [
"./src/**/*.ts",
"./tests/**/*.ts",
"./typings/index.d.ts"
]
}

O principal benefício de incluir um tscon g.json em um projeto é garantir


que cada execução do compilador seja idêntica comparação à execução
anterior e que todos os contribuidores do projeto estejam executando com
os mesmos sinalizadores. O compilador também tem vários sinalizadores
que alteram a rigidez do compilador quando se trata de veri cação de tipos
e se devem ser permitidos arquivos JavaScript. Essa é uma das melhores
partes do TypeScript, pois permite que o TypeScript seja adicionado a um
projeto existente sem exigir que o projeto inteiro seja convertido para o
TypeScript e totalmente tipado primeiro. Bandeiras como noImplicitAny,
quando false, não emitirá um aviso de compilador sobre uma variável que
não é anotada com um tipo ou onde um tipo não pode ser inferido. Com o
tempo, um projeto pode habilitar esse e outros sinalizadores, permitindo
que uma equipe trabalhe, incrementalmente, em direção ao código
totalmente tipado. Para novos projetos iniciados no TypeScript, recomenda-

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
se que o sinalizador strict seja habilitado para receber todos os benefícios
do TypeScript.

A propriedade lib no tscon g.json pode ser usada para especi car quais
bibliotecas padrão estão disponíveis para o projeto. Os valores aqui são
baseados no tipo de projeto e onde o projeto precisa ser executado. Por
exemplo, um projeto para Web provavelmente precisará acessar o DOM,
portanto, a inclusão de lib: [“dom”] garantirá a existência de document e
métodos como querySelector. Se estiver rodando em um ambiente
ES2016, ou um com os poly lls apropriados, “es2016” também pode ser
incluído. Se o seu projeto especi camente espera que os arrays tenham um
método .include, podemos incluir “es2016.array.include”. Isso permite a
personalização de como o TypeScript pode identi car o seu código,
comparando com o ambiente desejado em tempo de execução e se deve
lançar erros para o código atual, que pode não existir realmente no
ambiente em tempo de execução.

A partir do TypeScript 2.7, existe uma nova diretiva de referência para


lib, isolando a inclusão de uma biblioteca especí ca apenas no arquivo que
usa essa diretiva. Isso é bené co para isolar recursos novos/experimentais

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
em um único arquivo e não disponibilizá-los para o projeto inteiro.
Considere o seguinte exemplo:

/// <reference lib="es2016.array.include" />

[ 'foo', 'bar', 'baz' ].includes('bar'); // true

O compilador não lançará um erro sobre o uso Array.prototype.includes


neste módulo, porque ele contém a diretiva lib. No entanto, se outro arquivo
no projeto tentar usar esse método e a lib não for incluída no tscon g.json,
o compilador lançará um erro.

Muitos projetos também incluem um tslint.json para especi car


con gurações de linter e um arquivo package.json que é padrão na maioria
dos pacotes JavaScript.

O suporte a Glob foi adicionado para o TypeScript 2.0, facilitando o include


e exclude em grupo de arquivos seguindo padrões que aproveitam *, ?,

**/ .

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Observe que, a partir do TypeScript 2.1, o tscon g.json pode herdar de
outros arquivos de con guração, reduzindo a duplicação em aplicativos e
bibliotecas complexos. Isto é feito através da chave extends que tem um
caminho como um valor.

Utilizando let e const


O ES2015 introduz duas novas maneiras de declarar variáveis usando let e
const. É preferível declarar variável usando let ou const ao invés de var
porque as declarações var têm algumas regras de escopo incomuns em
comparação com outras linguagens. Ao contrário das variáveis declaradas
com var, aquelas declaradas com let são variáveis de “escopo de bloco”, que
não são visíveis fora de seu bloco mais próximo ou loop. Isso ajuda a evitar
colisões não intencionais na reutilização de nomes de variáveis. As variáveis
declaradas usando const são de escopo similar àquelas declaradas com let
— a grande diferença é que é um erro é retornado em tempo de compilação
se você tentar reatribuir o valor de uma const. No entanto, você ainda pode
alterar as propriedades dentro de um objeto mantido por uma variável
const. Utilizar const quando possível ajuda um programador a sinalizar sua

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
intenção sobre como essas variáveis se comportarão — o que torna o código
mais fácil de entender.

O TypeScript 2.0 adicionou a palavra chave readonly — que não permite a


reatribuição e implica uma propriedade não gravável/uma propriedade
acessível apenas via get. Isso não signi ca que os não-primitivos sejam
imutáveis.

Importação e exportação
Para começar a falar sobre como escrever o TypeScript, primeiro precisamos
entender como criar e carregar arquivos do TypeScript. Os arquivos
TypeScript usam a extensão de arquivo .ts e, como o AMD e o CommonJS ,
cada arquivo TypeScript representa nominalmente um único módulo. A
importação de módulos no TypeScript segue a API ES Modules (ESM):

import myModule from './myModule';

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Por padrão, a resolução do caminho de módulos para IDs de módulo
relativo é a mesma no TypeScript que no AMD e no CommonJS, em que a ID
do módulo é resolvida em relação ao diretório que contém o módulo de
referência. IDs de módulo absoluto funcionam de forma ligeiramente
diferente; primeiro, se houver uma declaração de módulo de ambiente
correspondente, seu valor será usado. Caso contrário, o compilador
percorre o sistema de arquivos, a partir do diretório que contém o módulo
de referência, procurando .ts, então .d.ts, em cada diretório pai, até
encontrar uma correspondência.

Antes do TypeScript 2.0, existia um suporte para duas maneiras de resolver


nomes de módulos: classic (um nome de módulo sempre é resolvido para
um arquivo, os módulos são pesquisados usando uma pasta walk) e node
(usa regras similares ao carregador de módulo Node.js). Infelizmente,
nenhuma abordagem resolve a abordagem de de nir módulos relativos a
um baseUrl, que é o que os sistemas AMD, como Dojo e RequireJS e
SystemJS usam, embora os esforços estejam em andamento na proposta de
padrões de URLs nomeados/mapeados.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Ao invés de introduzir um terceiro tipo de resolução de módulos para o
TypesSript 2.0, a equipe resolveu adicionar de nições de con guração para
resolver este problema: baseUrl, paths, e rootDirs.

paths só pode ser usado se baseUrl estiver de nido. Se pelo menos uma
dessas propriedades for de nida, o compilador do TypeScript tentará usá-
las para resolver os nomes dos módulos e, se falhar, recorrerá a uma
estratégia padrão.

Para exportar valores de um módulo, podemos utilizar a palavra-chave


export:

export function foo() {}


export let bar = 123;
export class MyClass {}

Importação de todo um módulo, pode ser feita usando *asterisco ()**, isso
fará com que as exportações do módulo quem disponíveis localmente com
os mesmos nomes: foo, bar, e MyClass. Para usar esses valores em outro

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
módulo, basta utilizar import para acessar o módulo e suas propriedades
exportadas:

import * from './myModule';

foo();
bar + 5; // = 128
new MyClass();

Para importar propriedades individuais, coloque os nomes das


propriedades com chaves:

import { foo } from './myModule';


import { bar, MyClass } from './myModule';

foo();
bar + 5; // = 128
new MyClass();

Você pode especi car uma exportação padrão adicionando a palavra-chave


default imediatamente após export:

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
export default class MyClass {}

Isso é equivalente a retornar um valor de uma função de fábrica (factory


function) no AMD ou atribuir um valor ao module.exports em CommonJS.
Para utilizar o módulo, você pode simplesmente importá-lo diretamente:

import MyClass from './MyClass';

let myInstance = new MyClass();

Fornecer um identi cador de importação sem chaves irá carregar a


importação padrão e será implicitamente nomeada ao que você especi car.
Outras importações podem ser nomeadas usando a palavra-chave as:

// AnotherClass = MyClass from MyClass.ts


import AnotherClass from './MyClass';

import { foo, bar as baz } from './myModule';

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Para anexar as exportações de um módulo a uma propriedade nomeada,
como quando você atribui propriedades ao objeto exports em AMD ou
CommonJS, podemos fornecer um alias para a importação com asterisco:

import * as foo from './myModule';

foo.foo();
foo.bar;
new foo.MyClass();

Observe que ao usar mixins com classes TypeScript (2.2+), há alguns


detalhes sutís descritos na seção sobre classes.

Açucares de linguagem
Antes de mergulhar nos recursos de tipagem estática do TypeScript, é
essencial revisar algumas das melhorias gerais feitas nas funções do
TypeScript, já que algumas dessas alterações tornam os recursos do sistema
de tipos mais fáceis de entender.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O TypeScript inclui quatro melhorias principais em funções: parâmetros
opcionais, valores de argumentos padrão, associar parâmetros
restantes e funções de seta.

Parâmetros opcionais agora podem ser de nidos pela su xação de um


identi cador de parâmetro com um ponto de interrogação:

function getRange(max, min, exclusive?) {


// ...
}

Aqui exclusive é um parâmetro opcional. Isso não tem sentido quando se


fala em JavaScript, já que todos os parâmetros são sempre opcionais, mas
no TypeScript, o compilador proíbe omitir os argumentos tipados, a menos
que eles sejam especi cados como opcionais ou tenham um valor padrão.

Um parâmetro opcional é essencialmente uma forma abreviada de


especi car unde ned como o valor padrão para um parâmetro. Tornar um
parâmetro opcional com um valor diferente é tão simples quanto atribuí-lo à

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
lista de parâmetros, ao invés de usar a abreviação de ponto de interrogação,
fazemos:

function getRange(max, min = 0, exclusive = false) {


// ...
}

Nesse caso, min é opcional e terá como padrão 0, e exclusive é opcional e


será padronizado com false.

O TypeScript também adiciona suporte para um parâmetro variádico no


nal com …rest, que coleta quaisquer argumentos extras passados para a
função em um único array nomeado:

function publish(topic, ...args): void {


// ...
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Neste caso, ao chamar publish(‘/foo’, ‘a’, ‘b’, ‘c’), topic uma string ‘/foo’ e
args seria um array [‘a’, ‘b’, ‘c’]. Observe que o uso desse recurso adiciona
um loop extra à sua função que é executada em cada chamada para coletar
argumentos restante no parâmetro nomeado, portanto, se você tem um
código crítico, para melhorar seu desempenho você deve continuar
utilizando diretamente o objeto arguments.

O TypeScript também inclui suporte para a função de seta do ES2015. Esse


novo tipo de função fornece uma nova sintaxe abreviada e também altera a
maneira como a palavra-chave this funciona, portanto, seu valor é obtido
do escopo léxico mais próximo, ao invés do objeto de contexto no qual está
sendo chamada, como as funções normais do JavaScript:

let obj = {
arrow: () => {
console.log(this);
},
regular: function () {
console.log(this);
}
};

obj.arrow(); // logs `window`


obj.regular(); // logs `obj`

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O TypeScript também inclui notações abreviadas de objetos que reduzem a
quantidade de código necessária para operações comuns com associar
objetos literais:

const foo = 'foo';


let a = {
// notação abreviada de identificador, igual à `foo: foo`
foo,

// notação abreviada para métodos, igual à `bar: function () {}`


bar() {

}
};

Desestruturação
Diversas variáveis podem ser atribuídas diretamente de um array:

let x, y;
[x, y] = [10, 20];

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Podemos encurtar:

let [x, y] = [10, 20];

Desestruturação também funciona com objetos:

let { place, location: [x, y] } = { place: 'test', location: [10, 20]


};
// variável local 'place' = 'test'
// variável local 'x' = 10
// variável local 'y' = 20

Outros recursos da linguagem


O TypeScript também inclui vários outros recursos das especi cações atuais
ou futuras do ECMAScript, incluindo:

Iteração de loop for..of

Strings de Template
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Tagged Strings de Template

Operador de Exponenciação

Generators e Protocolo de Iteração (No TS 1.6+ com exportação


ES2015, 2.3+ para exportação ES3/ES5 com --downlevelIteration )

async/await (TS 1.7+ com exportação ES2015, 2.1+ com exportação


ES3/ES5)

Iteração de loop for-await-of (TS 2.3+ para ES3/ES5 com --

downlevelIteration )

Expressões de Importação Dinâmica (TS 2.4+)

Variáveis opcionais para cláusula catc (TS 2.5+)

Tipos
Sem adicionar nenhuma indicação de tipo, as variáveis no TypeScript são
do tipo any, o que signi ca que elas podem conter qualquer tipo de dados,
assim como o JavaScript. A sintaxe básica para adicionar restrições de tipo
ao código no TypeScript é semelhante a:

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
function toNumber(numberString: string): number {
const num: number = parseFloat(numberString);
return num;
}

No código acima, a função toNumber aceita um parâmetro que deve ser


uma string e retorna um número. A variável num é explicitamente digitada
para conter um número (embora o TypeScript seja inteligente o su ciente
para saber que a função parseFloat padrão retorna um número e, portanto,
num é um número, ele é atribuído no momento em que é declarado). Os
tipos primitivos fornecidos pelo TypeScript são os mesmos tipos primitivos
do próprio JavaScript: any, number, string, boolean, void (isto é null ou
unde ned), never e a partir do TypeScript 3.0, unknown. Na maioria dos
casos, never é inferido em funções em que a análise de uxo de código
detecta algum código inacessível e, como desenvolvedor, você não precisa
se preocupar com isso. Por exemplo, se uma função for jogada ( throw ), ela
terá um tipo never. Já unknown, é um tipo de contrapartida segura do any,
garantindo que alguma veri cação de tipo seja executada antes que o valor
possa ser usado.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Ao escrever uma expressão (chamada de função, operação aritmética, etc.),
você também pode declarar explicitamente o tipo resultante da expressão, o
que é necessário se você estiver chamando uma função em que o TypeScript
não pode descobrir o tipo de retorno automaticamente. Por exemplo:

function numberStringSwap(value: any, radix: number = 10): any {


if (typeof value === 'string') {
return parseInt(value, radix);
}
else if (typeof value === 'number') {
return String(value);
}
}

const num = <number> numberStringSwap('1234');


const str = numberStringSwap(1234) as string;

Neste exemplo, o valor de retorno de numberStringSwap é ambíguo (any)


porque a função pode retornar mais de um tipo. Para remover a
ambigüidade, o tipo da expressão em que num está sendo atribuída pode
ser declarado explicitamente pre xando a expressão de chamada com num

= <seu-tipo-aqui> ... . Isso pode ser feito em qualquer lugar, desde que o

tipo que está sendo declarado seja compatível com o tipo da expressão; em

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
outras palavras, se o TypeScript soubesse que numberStringSwap
retornava um número, ao tentar a rmar o tipo com uma string, resultaria
em um erro do compilador como Cannot convert number to string , uma

vez que os dois tipos são incompatíveis. Uma sintaxe alternativa para
conversão de tipos usa a palavra-chave as, como mostrado na atribuição
para o valor str acima. Usar as é idêntico ao uso de <...> . No entanto, a

sintaxe <...> não está disponível em arquivos .tsx devido a sua


ambiguidade com TSX/JSX. Portanto, as é a sintaxe padrão e preferencial
para conversão de tipo.

Ao escrever código no TypeScript, é uma boa idéia adicionar explicitamente


os tipos às suas variáveis e funções onde o compilador não pode inferir o
tipo. Quando uma variável não é anotada e o tipo não pode ser inferido, é
dado um tipo any implícito . Ao compilar, a con guração “noImplicitAny”:
true na seção compilerOptions do tscon g.json evitará que tipos any
implícitos sejam adicionados em seu código (ou seja, áreas em que o
compilador não está sendo inteligente o bastante para descobrir o tipo
correto).

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O TypeScript também tem suporte para tipos literais de string. Esses são
úteis quando você sabe que o valor de um parâmetro pode corresponder a
uma lista de strings, por exemplo let easing: "ease-in" | "ease-out" |

"ease-in-out"; .

Declarações de classe local, interfaces, enums e tipos de alias também


podem aparecer dentro de declarações de função. O escopo para tipos locais
é bloqueado, semelhante a variáveis declaradas com let e const .

Tipos de Objeto
Além dos sete tipos primitivos, o TypeScript permite que tipos complexos
(como objetos e funções) sejam facilmente de nidos e usados como
restrições de tipo. Assim como objeto literais são a raiz da maioria das
de nições de objeto em JavaScript, o tipo literal de objeto são a maioria das
de nições de tipo de objeto em TypeScript. Em sua forma mais básica,
parece muito semelhante a um objeto literal de JavaScript normal:

let point: {
x: number;

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
y: number;
};

Neste exemplo, a variável point é de nida para aceitar qualquer objeto com
propriedades x e y. Observe que, diferentemente de um objeto literal
JavaScript, o tipo literal de objeto separa os campos usando ponto-e-vírgula,
e não vírgulas.

Quando o TypeScript compara dois tipos de objetos diferentes, para decidir


se eles correspondem ou não, isso é feito estruturalmente. Isso signi ca que,
ao invés de comparar os tipos, veri cando se os dois herdam o mesmo
objeto de restrição de base (como instanceof), as propriedades de cada
objeto são comparadas. Contanto que um determinado objeto tenha todas
as propriedades que são requeridas pela restrição na variável que está sendo
designada, elas são consideradas compatíveis (embora as atribuições de
objeto literal sejam tratadas mais estritamente como um caso especial):

let point: { x: number; y: number; };

point = { x: 0, y: 0 };
// OK, mesmas propriedades

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
point = { x: 'zero', y: 0 };
// Erro, tipo da propriedade `x` está errado

point = { x: 0 };
// Erro, faltando propriedade `y`

point = { x: 0, y: 0, z: 0 };
// Erro, atribuição literal deve contar apenas propriedades
declaradas

const otherPoint = { x: 0, y: 0, z: 0 };
point = otherPoint;
// OK, propriedades extras não são relevantes para atribuição não
literal

Para reduzir a duplicação de tipos, o operador typeof também pode ser


usado para de nir uma restrição de tipo. Por exemplo, se fôssemos
adicionar uma variável point2, ao invés de ter que escrever isso:

let point: { x: number; y: number; };


let point2: { x: number; y: number; };

Nós poderíamos simplesmente referenciar o tipo de point usando typeof:

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
let point: { x: number; y: number; };
let point2: typeof point;

Esse mecanismo ajuda a reduzir a quantidade de código necessário para


fazer referências ao mesmo tipo, mas há outra abstração ainda mais
poderosa no TypeScript para a reutilização de tipos de objetos: interfaces.
Uma interface é, em essência, um tipo literal de objeto nomeada. Vamos
alterar o exemplo anterior para usar uma interface:

interface Point {
x: number;
y: number;
}

let point: Point;


let point2: Point;

Essa alteração permite que o tipo Point seja usado em vários locais dentro
do código sem precisar rede nir os detalhes do tipo repetidas vezes.
Interfaces também podem estender outras interfaces ou classes usando a

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
palavra-chave extends para compor tipos mais complexos a partir de tipos
simples:

interface Point3d extends Point {


z: number;
}

Neste exemplo, o tipo Point3d resultante consistiria nas propriedades x e y


da interface Point, além da nova propriedade z.

Métodos e propriedades em objetos também podem ser especi cados como


opcionais, da mesma forma que os parâmetros de função podem ser
opcionais:

interface Point {
x: number;
y: number;
z?: number;
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Aqui, ao invés de especi car uma interface separada para um ponto
tridimensional, simplesmente tornamos a propriedade z da interface
opcional; a veri cação de tipo resultante seria assim:

let point: Point;

point = { x: 0, y: 0, z: 0 };
// OK, mesmas propriedades

point = { x: 0, y: 0 };
// OK, mesmas propriedades, parâmetro opcional omitido

point = { x: 0, y: 0, z: 'zero' };
// Erro, tipo da propriedade `z` está errado

Até agora, examinamos os tipos de objetos com propriedades, mas não


especi camos como adicionar um método a um objeto. Como as funções
são objetos de primeira classe em JavaScript, é possível usar a sintaxe de
propriedade, o TypeScript também fornece uma sintaxe abreviada para
especi car métodos, o que se torna muito conveniente quando começamos
a trabalhar com classes:

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
interface Point {
x: number;
y: number;
z?: number;
toGeo(): Point;
}

Neste exemplo, adicionamos um método toGeo na interface Point, que não


aceita argumentos e retorna outro objeto Point. Como as propriedades, os
métodos também podem ser opcionais, colocando um ponto de
interrogação após o nome do método:

interface Point {
// ...
toGeo?(): Point;
}

Objetos destinados a serem usados como mapas de hash ou listas ordenadas


podem receber uma assinatura de índice, que permite que chaves
arbitrárias sejam de nidas em um objeto:

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
interface HashMapOfPoints {
[key: string]: Point;
}

Neste exemplo, de nimos um tipo em que qualquer chave pode ser


de nida, desde que o valor atribuído seja do tipo Point. Como no
JavaScript, só é possível usar string ou number como o tipo da assinatura
do índice.

Para tipos de objeto sem uma assinatura de índice, o TypeScript permitirá


apenas que as propriedades sejam de nidas explicitamente no tipo. Se você
tentar atribuir a uma propriedade que não existe no tipo, você receberá um
erro do compilador. Porém, algumas vezes, você não quer adicionar
propriedades dinâmicas a um objeto sem uma assinatura de índice. Para
isso, você pode usar a notação de array para de nir a propriedade no
objeto: a['foo'] = 'foo'; . Observe, no entanto, que o uso dessa solução

alternativa sobressai o sistema de tipos para essas propriedades, portanto,


faça isso apenas como último recurso.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O Typescript 2.7 adiciona a capacidade de ter propriedades de nomes
constantes nos tipos. Isso signi ca que as interfaces podem ser de nidas
usando strings constantes, números ou literais de símbolo.

const Foo = 'Foo';


const Bar = 'Bar';
const Baz = Symbol();

interface MyInterface {
[Foo]: number;
[Bar]: string;
[Baz]: boolean;
}

Tipo “object” em TS 2.2+


O TypeScript 2.2 adiciona o tipo object que corrige uma limitação anterior
na de nição de tipo em que algo pode ser um tipo Object não primitivo.
Não era possível lidar com esse cenário em versões anteriores do TypeScript
porque number, string e boolean podem ser atribuídos a Object. O novo
tipo object (observe as letras minúsculas) implica em um tipo que é
atribuível ao Object, exceto para primitivos.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Tipos de Tupla
Embora o JavaScript em si não tenha tuplas, o TypeScript possibilita emular
tuplas tipadas usando Arrays. Se você quiser armazenar um ponto como
uma tupa (x, y, z) ao invés de um objeto, isso pode ser feito especi cando
um tipo de tupla em uma variável:

let point: [ number, number, number ] = [ 0, 0, 0 ];

O TypeScript 3.0 adiciona melhor suporte para os tipos de tupla, permitindo


que elas sejam usadas com expressões de atribuição restante (rest params)
e propagação (spread operator), e permitindo elementos opcionais:

function draw(...point: [ number, number, number? ]): void {


const [ x, y, z ] = point;
console.log('point', ...point);
}

draw(100, 200); // loga: point 100, 200


draw(100, 200, 75); // loga: point 100, 200, 75
draw(100, 200, 75, 25); // Erro: Espera 2-3 argumentos mas recebeu 4

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
No exemplo acima, a função draw pode aceitar valores para x, y e,
opcionalmente z. Os tipos de tuplas têm um comprimento xo a partir do
TypeScript 2.7, mas também contêm a capacidade de marcar um valor
dentro da tupla como opcional.

Tipos de Função
Como as funções em JavaScript são objetos de primeira classe, a sintaxe
literal do tipo de objeto também pode ser usada para especi car que um
objeto deve ser uma função. Para fazer isso, a mesma sintaxe do método
mostrada acima toGeo é usada, mas com o nome do método deixado em
branco:

let printPoint: {
(point: Point): string;
};

Aqui, printPoint é de nido para aceitar uma função que recebe um objeto
de ponto e retorna uma string.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Como as funções são tão comuns em JavaScript, existe uma sintaxe de tipo
para abreviar uma função especí ca no TypeScript, que pode ser usada para
de nir funções com uma única assinatura de chamada:

let printPoint: (point: Point) => string;

Observe que usamos a seta ( => ), que vem da função de seta do ES2015,
para de nir o tipo de retorno da função ao invés dos dois pontos. Os dois
pontos ( : ) são usados para de nir o tipo de retorno de um método de nido
dentro de um tipo de objeto literal, interface ou classe, enquanto que as
setas são usadas pelo tipo de função abreviada mostrado aqui. Isso é um
pouco confuso no início, mas ao trabalhar com o TypeScript, você
descobrirá que é fácil saber quando um ou outro deve ser usado. Por
exemplo, no exemplo acima, usar dois pontos pareceria errado porque
resultaria em dois dois pontos diretamente dentro da declaração:

let printPoint: (point: Point): string

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Agora que conhecemos a sintaxe do tipo de função, voltando à nossa
de nição Point, de nimos toGeo como uma propriedade ao invés de um
método:

interface Point {
x: number;
y: number;
z?: number;
toGeo: () => Point;
}

As funções também podem ser tipadas como construtores colocando a


palavra-chave new antes do tipo de função:

let Point: { new (): Point; };


let ShorthandEquivalent: new () => Point;

Neste exemplo, qualquer função atribuída Point ou ShorthandEquivalent


precisaria ser um construtor que cria objetos Point.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Como a sintaxe literal do objeto nos permite de nir objetos como funções,
também é possível de nir tipos de função com propriedades ou métodos
estáticos (como a função JavaScript String , que também possui um método

estático String.fromCharCode ):

let Point: {
new (): Point;
fromLinear(point: Point): Point;
fromGeo(point: Point): Point;
};

Aqui, de nimos Point aceitando um construtor que também precisa ter os


métodos estáticos Point.fromLinear e Point.fromGeo . A única maneira de

realmente fazer isso é de nir uma classe que implemente Point e tenha os
métodos estáticos fromLinear e fromGeo; Vamos ver como fazer isso mais
tarde, quando discutirmos class em profundidade.

Funções sobrecarregadas

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
NOTA: Em inglês conhecidos como — overloaded functions, functions overload,
etc

Anteriormente, criamos uma função numberStringSwap de exemplo que


converte entre números e strings:

function numberStringSwap(value: any, radix: number):any {


if (typeof value === 'string') {
return parseInt(value, radix);
}
else if (typeof value === 'number') {
return String(value);
}
}

Neste exemplo, a ambiguidade existe na assinatura de chamada porque o


tipo de retorno é any. No entanto, sabemos que essa função retorna uma
string quando é passado um número e um número quando é passado uma
string. Para ajudar o compilador do TypeScript a saber o que sabemos,
podemos usar sobrecargas de função para eliminar a ambigüidade da
assinatura de chamada e restaurar a veri cação de tipo no valor de retorno.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Uma maneira de escrever a função acima, em que a tipagem é tratada
corretamente, é:

function numberStringSwap(value: number, radix?: number): string;


function numberStringSwap(value: string): number;
function numberStringSwap(value: any, radix: number = 10): any {
if (typeof value === 'string') {
return parseInt(value, radix);
}
else if (typeof value === 'number') {
return String(value);
}
}

Com as assinaturas de chamadas extras, o TypeScript agora sabe que


quando for passado a função uma string, ela retorna um número e vice-
versa. Você também pode usar tipos de união em alguns casos, ao invés de
sobrecargas de função, que serão discutidas posteriormente neste guia.

É extremamente importante ter em mente que a implementação real da


função deve ter uma interface que corresponda ao menor denominador
comum de todas as assinaturas de sobrecarga. Isso signi ca que se um
parâmetro aceita vários tipos, como no exemplo o value, a implementação

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
deve ter um tipo que englobe todas as opções possíveis. No caso de
numberStringSwap, porque string e number não tem base comum, o tipo
de value deve ser any.

Da mesma forma, se diferentes sobrecargas aceitarem diferentes números


de argumentos, a implementação real deve ser escrita de modo que
quaisquer argumentos que não existam em todas as assinaturas de
sobrecarga sejam opcionais. Em numberStringSwap, isso signi ca que nós
temos que fazer o argumento radix ser opcional na implementação real.
Isso é feito especi cando um valor padrão.

Não seguir essas regras resultará em um erro genérico de “Assinatura de


sobrecarga não é compatível com de nição de função” (Overload signature
is not compatible with function de nition).

Note que mesmo que nossa função, totalmente de nida, use o tipo any para
value, ao tentar passar outro tipo (como um booleano) para este
parâmetro, fará com que o TypeScript lance um erro, pois somente as
assinaturas sobrecarregadas são usadas para veri cação de tipo. Em um

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
caso em que mais de uma assinatura corresponderia a uma determinada
chamada, a primeira sobrecarga listada no código-fonte vencerá:

function numberStringSwap(value: any): any;


function numberStringSwap(value: number): string;

numberStringSwap('1234');

Aqui, embora a segunda assinatura de sobrecarga seja mais especí ca, a


primeira será usada. Isso signi ca que você sempre precisa veri car se o seu
código-fonte está devidamente ordenado para que as sobrecargas preferidas
sejam listadas primeiro.

As sobrecargas de função também funcionam em literais, interfaces e


classes de tipo de objeto:

let numberStringSwap: {
(value: number, radix?: number): string;
(value: string): number;
};

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Observe que, como estamos de nindo um tipo e não estamos criando uma
declaração de função real, a implementação real de numberStringSwap é
omitida.

O TypeScript também permite especi car diferentes tipos de retorno


quando uma string exata é fornecida como um argumento para uma
função. Por exemplo, a declaração de ambiente createElement do
TypeScript para o método do DOM se parece com isto:

createElement(tagName: 'a'): HTMLAnchorElement;


createElement(tagName: 'abbr'): HTMLElement;
createElement(tagName: 'address'): HTMLElement;
createElement(tagName: 'area'): HTMLAreaElement;
// ... etc.
createElement(tagName: string): HTMLElement;

Isso signi ca que, em TypeScript, quando você chama


document.createElement(‘video’), por exemplo, o TypeScript sabe que o
valor de retorno é um HTMLVideoElement e será capaz de garantir que
você esteja interagindo corretamente com a API de vídeo DOM sem a
necessidade de a rmar o tipo.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Tipos rigorosos para Funções em TS 2.6+
Por padrão, o TypeScript é negligente ao veri car os parâmetros do tipo de
função. Considere o seguinte exemplo:

class Animal { breath() { } }


class Dog extends Animal { bark() {} }
class Cat extends Animal { meow() {} }

let f1: (x: Animal) => void = (x: Animal) => x.breath();
let f2: (x: Dog) => void = (x: Dog) => x.bark();
let f3: (x: Cat) => void = (x: Cat) => x.meow();

f1 = f2;
const c = new Cat();
f1(c); // Erro no Runtime

Se fôssemos de nir f1 = f2 , isso resultaria em um erro em tempo de

execução se nós passássemos Cat para a função, mesmo que Cat seja um
Animal, ele tentaria chamar .bark , o que os gatos não conseguem fazer. No

entanto, o TypeScript não apresentará um erro por padrão. Isso ocorre


porque os tipos de função no TypeScript são bivariantes. Para corrigir isso, a
equipe do TypeScript adicionou um novo sinalizador --

strictFunctionTypes , que lançará um erro na atribuição f1 = f2 .

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Tipos Genéricos
O TypeScript inclui o conceito de tipos genéricos, que pode ser interpretado
como um tipo que deve incluir ou fazer referência a outro tipo para ser
concluído. Dois tipos genéricos muito comuns que você vai encontrar são
Array e Promise.

A sintaxe de um tipo genérico é GenericType . Por exemplo, um tipo "array

de strings" seria Array e um tipo "promise que resolve para um número"


seria Promise . Tipos genéricos podem exigir mais de um tipo especí co
como Converter , mas isso é extremamente incomum. Os marcadores de

posição de tipos dentro dos colchetes são chamados de parâmetros de


tipo. Ao contrário dos tipos de objetos não genéricos, os tipos genéricos só
podem ser criados com interfaces ou classes.

Como arrays são o tipo mais comum de tipo genérico, é mais fácil explicar
como criar seus próprios tipos genéricos usando uma interface parecida
com um array como exemplo:

interface Arrayish<T> {
map<U>(callback: (value: T, index: number, array: Arrayish<T>) =>
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
U, thisArg?: any): Array<U>;
}

Neste exemplo, Arrayish é de nido como um tipo genérico com um único


método map, que corresponde ao método Array#map do ECMAScript 5. O
método map tem um parâmetro de tipo próprio U , que é usado para indicar

que o tipo de retorno da função de callback precisa ser do mesmo tipo que o
valor de retorno de map.

Seria algo como isto:

const arrayOfStrings: Arrayish<string> = [ 'a', 'b', 'c' ];

const arrayOfCharCodes: Arrayish<number> =


arrayOfStrings.map(function (value: string): number {
return value.charCodeAt(0);
});

Aqui, arrayOfStrings é de nido como sendo um Arrayish contendo strings,


e arrayOfCharCodes é de nido como sendo um Arrayish contendo
números. Chamamos map no array de strings, passando uma função

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
callback que retorna números. Se o callback fosse alterado para retornar
uma string ao invés de um número, o compilador geraria um erro
informando que os tipos não são compatíveis, pois arrayOfCharCodes é
explicitamente tipado e faz uso de um parâmetro de tipo para determinar o
valor retornado pelo callback, garantindo a compatibilidade no compilador.

Como arrays são um caso comum de tipos genéricos, TypeScript fornece


uma forma abreviada para arrays: SpecificType[] . Perceba porém, que a

ambigüidade pode surgir ocasionalmente ao usar essa abreviação. Por


exemplo, o tipo é () => boolean[] , um array de funções que retorna

booleanos ou é uma única função que retorna um array de booleanos?

A resposta correta é a última; para representar o primeiro, você precisaria


escrever Array<() => boolean> ou { (): boolean; }[] .

O TypeScript também permite que os parâmetros de tipo sejam restritos a


um tipo especí co usando a palavra-chave extends dentro do parâmetro de
tipo, como interface PointPromise . Nesse caso, somente um tipo que

correspondesse estruturalmente a Point poderia ser usado com esse tipo


genérico; tentar usar outra coisa, tipo string , causaria um erro de tipo.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Na versão 2.3, o Typescript adicionou a capacidade de declarar um tipo
padrão para tipos genéricos. Isso é muito útil para funções em que o tipo de
retorno depende de um parâmetro, mas você deseja que o parâmetro seja
opcional. Por exemplo, se quiséssemos uma função que criasse uma
Arrayish baseada nos argumentos passados mas com padrão para string
quando nenhum argumento fosse passado, antes de 2.3 teríamos que
escrever:

function createArrayish(): Arrayish<string>;


function createArrayish<T>(...args: T[]): Arrayish<T>;
function createArrayish(...args: any[]): Arrayish<any> {
return args;
}

A partir da versão 2.3+, podemos escrever:

function createArrayish<T = string>(...args: T[]): Arrayish<T> {


return args;
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Tipos de União
O tipo de união é usado para indicar que um parâmetro ou variável pode
conter mais de um tipo. Por exemplo, se você quiser ter uma função como
document.getElementById, mas que também permita que você passe um
elemento, como a função byId do Dojo, você poderia fazer isso usando um
tipo de união:

function byId(element: string | Element): Element {


if (typeof element === 'string') {
return document.getElementById(element);
}
else {
return element;
}
}

O TypeScript é inteligente o su ciente para tipar contextualmente a variável


element dentro do bloco if para ser do tipo string e para ser do tipo
Element no bloco else. O mecanismo de redução de tipos é chamado de
Guardas de Tipo (Type Guards).

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Tipos de Intersecção
Os tipos de interseção exigem que o valor atenda ao contrato de todos os
membros do tipos. Por exemplo:

interface Foo {
name: string;
count: number;
}

interface Bar {
name: string;
age: number;
}

export type FooBar = Foo & Bar;

Uma ressalva é que você pode acidentalmente criar tipos inutilizáveis:

interface Foo {
count: string;
}

interface Bar {
count: number;
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
export type FooBar = Foo & Bar;
/* FooBar.count é do tipo `string & number` */

Tipando o valor de “this”


O contexto ou valor de this em uma função, método, classe ou interface
pode ser de nido. Em uma função ou método, this é um falso primeiro
parâmetro. Você também pode usar parâmetros this para declarar como
callbacks são chamados.

Para evitar reverter o comportamento de tipagem de this da versão anterior


do TypeScript, você pode usar o sinalizador --noImplicitThis no
compilador.

Tipos Mapeados em TS 2.1+


Os Tipos Mapeados permitem a criação de novos tipos com base nos tipos
existentes, mapeando efetivamente um tipo existente e retornando um
novo. Isso permite a transformação de cada propriedade de um tipo
existente em um novo, reduzindo a duplicação de tipos. Um tipo de exemplo

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
pode ser um chamado Stringify, que pegará um tipo T e transformará cada
propriedade desse tipo em um valor seja string :

type Stringify<T> = {
[P in keyof T]: string;
};

interface Point { x: number; y: number; }

type StringPoint = Stringify<Point>;

const pointA: StringPoint = { x: '4', y: '3' };


// válido

Tipos “Mapped”, “Partial”, “Readonly”, “Record” e


“Pick” em TS 2.1+
Partial, Readonly, Record e Pick são tipos mapeados que são tão comuns que
o TypeScript fornece isso para você. Um tipo Parcial é aquele em que
tomamos um tipo existente, mas todas as suas propriedades são opcionais.
Isso é comum para APIs que aceitam um pacote de propriedades como um
parâmetro:

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
setState(this: StoreMixin, newState: Partial<State>): void {
const { properties: { store, id } } = this;

if (id || newState['id']) {
store.patch(assign( { id }, newState))
.then(() => id ? store.get(id) : store.fetch())
.then((state: State) => {
replaceState(this, state);
});
}
else {
throw new Error('Unable to set state without a specified
`id`');
}
}

Com os tipos Mapped, podemos simpli car a sintaxe para expressar isso,
iterando sobre o tipo original usando keyof , como uma forma de criar

rapidamente o novo tipo parcial. Os tipos mapeados também são úteis para
transformar tipos. Por exemplo, transformando um grupo de propriedades
síncronas em instâncias de Promise:

type ToPomise<T> = { [K in typeof T]: Promise<T[K]> };

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O TypeScript 2.8 adiciona a capacidade de adicionar ou remover
modi cadores readonly ou ? nas propriedades mapeadas. Isso é feito
usando + e - para indicar se o modi cador deve ser adicionado ou
removido:

type MutableRequired<T> = { -readonly [P in keyof T]-?: T[P] };


type ReadonlyPartial<T> = { +readonly [P in keyof T]+?: T[P] };

interface Point { readonly x: number; y: number; }

const pointA: ReadonlyPartial<Point> = { x: 4 };


pointA.y = 3; // Erro: readonly

const pointB: MutableRequired<Point> = { x: 4, y: 3 };


pointB.x = 2; // Válido

O TypeScript 3.1 também introduz a capacidade de mapear os tipos de


tupla e retornar um novo tipo de tupla. Considere o exemplo a seguir, onde
um tipo de tupla para Point é de nido. Suponha que, em alguns casos, os
pontos sejam realmente Promises que resolvam os objetos Point . O

TypeScript permite a criação do último tipo a partir do primeiro:

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
type ToPromise<T> = { [K in typeof T]: Promise<T[K]> };
type Point = [ number, number ];
type PromisePoint = ToPromise<Point>;

const point: PromisePoint = [ Promise.resolve(2), Promise.resolve(3)


]; // Válido
}

Tipos Condicionais em TS 2.8+


Os tipos condicionais permitem que um tipo seja de nido dinamicamente
com base em uma condição fornecida. Todos os tipos de condicionais
seguem o mesmo formato: T extends U ? X : Y . Isso deve parecer familiar

para você, pois é a sintaxe de uma declaração ternária. O que esta


declaração signi ca é que se T é atribuível a U , então de na o tipo para X.

Caso contrário, de na o tipo para Y . Isso pode parecer simples no começo,

mas é uma maneira muito poderosa de garantir que os tipos apropriados


sejam fornecidos para o seu código.

Considere o seguinte exemplo em que gostaríamos de de nir tipos para uma


função que aceita um número ou uma sequência.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
declare function addOrConcat(x: number | string): number | string;

Os tipos aqui são su ciente, mas não transmitem verdadeiramente o


signi cado ou a intenção do código. Se o argumento é um number então o
tipo de retorno também será number , e da mesma forma para string . Para

corrigir isso, podemos usar a sobrecarga de funções:

declare function addOrConcat(x: string): string;


declare function addOrConcat(x: number): number;
declare function addOrConcat(x: number | string): number | string;

No entanto, temos que digitar muito e pode ser tedioso mudar no futuro.
Aqui entra os tipos condicionais! Usando a sintaxe ternária dos tipos
condicionais acima, podemos simpli car nossa assinatura de função para o
seguinte:

declare function addOrConcat<T extends number | string>(x: T): T


extends number ? number : string;

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Esta assinatura de função está usando tipos genéricos, indicando que T será
um number ou um string . Este será o valor para o argumento. Em seguida,

os tipos condicionais são usados para determinar o tipo de retorno,


informando que a função retornará um number se um for passado, caso
contrário, uma string .

O TypeScript também vem com alguns tipos condicionais comuns que


servem para lidar com situações de uso de tipos condicionais, mostrando
seu verdadeiro poder.

Exclude : excluir de T qualquer coisa que seja atribuível a U

Extract : extrair de T qualquer coisa que seja atribuível a U

NonNullable : excluir null e undefined

ReturnType : obter o tipo de retorno de uma função

InstanceType : obter o tipo de instância de uma função construtora

type ExcludeExample = Exclude<string | number | Point, string |


Point>; // number
type ExtractExample = Extract<string | number | Point, string |

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Point>; // string | Point
type NonNullableExample = NonNullable<string | number | null |
undefined | void>; // string | number
type ReturnTypeExample = ReturnType<() => boolean>; // boolean

class Renderer {}
type InstanceOfExample = InstanceType<typeof Renderer>; // Renderer

Guardas de Tipo
NOTA: Em inglês conhecidos como — type guards

Guardas de tipo permitem o limitar os tipos dentro de um bloco


condicional. Isso é essencial quando se trabalha com tipos que podem ser
uniões de dois ou mais tipos ou onde o tipo não é conhecido até o tempo de
execução. Para fazer isso de uma maneira que também é compatível com o
código JavaScript que será executado em tempo de execução, o sistema de
tipos do TypeScript utiliza os operadores typeof , instanceof , e in (a partir
do TS 2,7+) do JavaScript. Dentro de um bloco condicional usando uma
dessas veri cações, é garantido que o valor veri cado é desse tipo e os
métodos que existiriam nesse tipo podem ser usados com segurança.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Utilizando “typeo ” como guarda de tipos
O guarda de tipo typeof irá tipar o resultado utilizando o operador do
JavaScript typeof . Se a execução entrar no bloco condicional, o TypeScript

pode assumir corretamente que o valor é do tipo que está sendo veri cado.
No entanto, se a execução continuar no bloco else , o TypeScript pode

assumir que o valor não é desse tipo e, no caso de um tipo de união, é a


alternativa:

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


if (typeof x === 'string') {
// `x` é garantido ser uma `string`, podemos utilizar
`.toLowerCase`
return x.toLowerCase();
} else {
// caso contrário, `x` é um array de strings e podemos
utilizar `.reduce`
return x.reduce((val: string, next: string) => {
return val += `, ${next.toLowerCase()}`;
}, '');
}
}

Utilizando “instanceo ” como guarda de tipos

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O guarda de tipo instanced usará o operador instanceof do JavaScript
para restringir os tipos dentro de uma instrução condicional. Assim como o
uso de typeof acima, se o resultado desse tipo de veri cação for verdadeiro,
o TypeScript pode inferir corretamente que a variável em questão é desse
tipo dentro do bloco condicional.

function clearElement(element: string | HTMLElement) {


if (element instanceof HTMLElement) {
// garantimos que `element` é do tipo `HTMLElement`
// então podemos acessar a propriedade `.innerHTML`
element.innerHTML = '';
} else {
// caso contrário, `element` é uma `string` e podemos passá-
la diretamente para `document.querySelector`
const el = document.querySelector(element);
el && el.innerHTML = '';
}
}

Utilizando “in” como guarda de tipos


Esse tipo de proteção restringe o tipo dentro de uma condição, veri cando
se existe uma propriedade na variável. Se o resultado for true , o tipo de

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
variável será restringido para corresponder ao tipo que contém o valor
veri cado.

interface Point {
x: number;
y: number;
}

interface Point3d extends Point {


z: number;
}

function plot(point: Point) {


if ('z' in point) {
// point é um `Point3D`
// ...
} else {
// point é um `Point`
// ...
}
}

Classes
Um dos principais recursos do TypeScript que ainda precisamos discutir é a
sintaxe de herança baseada em classes. O sistema de classes no TypeScript

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
usa um modelo de herança única que deve ser familiar a qualquer
programador que tenha trabalhado com qualquer linguagem baseada em
classes. É importante observar que as classes JavaScript são, basicamente,
um açúcar sintático sobre o sistema de herança baseado em protótipo e não
introduzem um novo modelo de herança orientado a objeto ao JavaScript.

Uma de nição básica de classe é assim:

class Proxy {
constructor(kwArgs: {}) {
for (let key in kwArgs) {
this[key] = kwArgs[key];
}
}

get(key: string):any {
return this[key];
}

set(key: {}): void;


set(key: string, value: any): void;
set(key: any, value?: any): void {
// ...
}
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Na maior parte, as classes no Typescript são semelhantes às classes no
ES2015. O método especial constructor representa a função JavaScript
usada como construtor quando compilada de volta ao JavaScript. Se
desejado, esta função pode retornar um valor para usar como a instância,
assim como o JavaScript, mas ao contrário de todos os outros métodos de
uma classe, constructor não pode ter um tipo de retorno de nido; o tipo de
retorno do método construtor é sempre a própria classe.

A subclasse funciona como outros sistemas de herança baseados em classes,


usando a palavra-chave extends para criar um subtipo e o identi cador
super para se referir à superclasse:

class Stateful extends Proxy {


constructor(kwArgs: {}) {
super(kwArgs);
}

get(key: string): any {


let getter: string = '_' + key + 'Getter';
return this[getter] ? this[getter]() : super.get(key);
}
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Onde o TypeScript difere das classes do ES2015 atualmente está no uso de
campos não-método, no entanto, há uma proposta do estágio 3 para
adicionar isso ao JavaScript. Classes em TypeScript pode também de nir as
propriedades como sendo private , protected e/ou static :

class Animal extends Stateful {


protected _happy: boolean;

pet(): void {
this._happy = true;
}
}

class Dog extends Animal {


static isDogLike(object: any): boolean {
return object.bark && object.pet;
}

private _loudBark: boolean;

bark(): string {
let noise = this._happy ? 'woof' : 'grr';
if (this._loudBark) {
noise = noise.toUpperCase();
}

return noise;
}
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Devido a privacidade da propriedade ser uma restrição de tempo de
compilação e não uma restrição de tempo de execução, é uma boa idéia
continuar seguindo as convenções de JavaScript para propriedades private

e pre xar com um sublinhado, caso seu código TypeScript compilado for
consumido por alguém que esteja escrevendo JavaScript puro.

Os valores padrão da propriedade também podem ser especi cados em uma


de nição de classe. O valor padrão de uma propriedade pode ser qualquer
expressão de atribuição, não apenas um valor estático, e será executada
toda vez que uma nova instância for criada:

class DomesticatedDog extends Dog {


age: number = Math.random() * 20;
collarType: string = 'leather';
toys: Toy[] = [];
}

No entanto, existem algumas advertências que vêm com a de nição de


propriedades padrão dessa maneira. Notavelmente, se você de niu uma
função construtora em uma subclasse, você deve chamar super() antes de
qualquer outra coisa dentro do construtor, o que signi ca que você não
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
pode executar operações antes que o construtor da superclasse seja
executado, e as propriedades padrão de sua subclasse não serão de nidas
até o construtor da superclasse ser executado. A alternativa para isso é
simplesmente de nir os padrões na função construtora:

class DomesticatedDog extends Dog {


age: number;
collarType: string;
toys: Toy[];

constructor(kwArgs: {}) {
this.age = Math.random() * 20;
this.collarType = 'leather';
this.toys = [];
super(kwArgs);
}
}

As propriedades padrão são sempre de nidas pelo TypeScript da mesma


maneira acima, o que signi ca que essas duas de nições de classe são
equivalentes da perspectiva de como as propriedades padrão são de nidas.
Como resultado, você não precisa se preocupar com objetos ou arrays sendo
compartilhados entre instâncias, como aconteceria se eles estivessem
especi cados no protótipo, o que ajuda em um ponto comum de confusão
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
para pessoas que usam bibliotecas de herança em JavaScript “class-like” que
especi cam propriedades no protótipo.

Mixins e Herança múltipla


No TypeScript, as interfaces também podem estender classes, o que pode
ser útil ao compor tipos complexos, especialmente se você estiver
acostumado a escrever mixins e usar herança múltipla:

interface Chimera extends Dog, Lion, Monsterish {}

class MyChimera implements Chimera {


bark: () => string;
roar: () => string;
terrorize(): void {
// ...
}

// ...
}
MyChimera.prototype.bark = Dog.prototype.bark;
MyChimera.prototype.roar = Lion.prototype.roar;

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Neste exemplo, temos duas classes ( Dog , Lion ) e uma interface

( Monsterish ) foram combinadas em uma nova interface Chimera e, em


seguida, uma classe MyChimera implementa essa interface, delegando de
volta para as funções corretamente das classes originais. Observe que os
métodos barke e roar são realmente de nidos como propriedades ao invés
de métodos; isso permite que a interface seja "totalmente implementada"
pela classe, apesar da implementação real não existir de fato dentro da
de nição de classe. Esse é um dos casos de uso mais avançados para classes
no TypeScript, mas permite uma reutilização de código extremamente
robusta e e ciente quando usado corretamente.

O TypeScript 2.2 fez várias alterações para facilitar o trabalho com mixins e
classes de composição. Ao invés de adicionar uma nova gramática a classes
que posteriormente possam entrar em con ito com a próxima versão do ES,
a equipe do TypeScript obteve esse resultado removendo algumas das
restrições nas classes. Por exemplo, agora é possível estender de um valor
que constrói um tipo de interseção. O modo como as assinaturas dos tipos
de interseção se combinam também mudou.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Enumeráveis
NOTA: Em inglês conhecidos como — enumerables

O TypeScript adiciona um tipo básico de enum que permite uma


representação e ciente de conjuntos de valores explícitos. Por exemplo, da
especi cação do TypeScript, uma enumeração de estilos possíveis para
aplicar ao texto pode ter esta aparência:

enum Style {
NONE = 0,
BOLD = 1,
ITALIC = 2,
UNDERLINE = 4,
EMPHASIS = Style.BOLD | Style.ITALIC,
HYPERLINK = Style.BOLD | Style.UNDERLINE
}

if (value & Style.BOLD) {


// cuidando de BOLD, EMPHASIS, e HYPERLINK
}

Quando os valores do enumerador são inteiros, você pode usar, como


mostrado acima, o operador bitwise OR para criar valores de bitmask e usar

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
o operador bitwise AND para veri car se um valor está de nido no bitmask.
Como acima, você também pode de nir explicitamente o valor de um
membro de um enum usando a atribuição. Enums que usam operadores
bitwise devem ser especi cados para usar explicitamente valores 2n para
cada item; enums são normalmente valores simples indexados em 0.

Antes da versão 2.4, os valores de enumeradores eram restritos pelo


compilador a números. Na versão 2.4 e além, os valores de enumeradores
podem ser strings:

enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE"
}

Os tipos numéricos enumeráveis no TypeScript são mapas bidirecionais,


portanto, você pode determinar o nome de um valor enumerado
pesquisando-o no objeto enum. Usando o exemplo Style acima, Style[1]

iria resultar para 'BOLD' . As enums inicializadas por string não podem ser

mapeadas inversamente.
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O tipo const enum é o mesmo que um enumerável regular, exceto que o
compilador substitui todas as referências a valores enumeráveis por valores
literais ao invés de gerar código representando as estruturas enumeráveis
no tempo de execução.

Aliases — “Pseudônimos” em Português


Aliases de tipos mais robustos podem ser usados, que usam a palavra-chave
type para fornecer o mesmo tipo de alias, mas também podem suportar a
nomeação de outros tipos primitivos:

import * as foo from './foo';


type Foo = foo.Foo;
type Bar = () => string;
type StringOrNumber = string | number;
type PromiseOrValue<T> = T | Promise<T>;

function convert(value: StringOrNumber): string {


return String(value);
}

function when<T>(value: PromiseOrValue<T>): Promise<T> {


if (value instanceof Promise) {
return value;
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
return Promise.resolve(value);
}

Declarações de Ambiente
Para usar o código JavaScript existente com o TypeScript, o compilador
precisa saber quais módulos e variáveis vêm de fora do TypeScript. Para
fazer isso, o TypeScript introduz o conceito de uma declaração de ambiente
— uma declaração especial que fornece informações de tipo sobre APIs que
existem “no ambiente” de execução do aplicativo.

Declarações de ambiente são criadas adicionando os pre xos normais do


TypeScript como module , var , let , const , function , class , ou enum

declarado com a palavra-chave declare , o que indica ao compilador que a

instrução se destina para o tipo de ambiente. Como as declarações de


ambiente existem inteiramente para o benefício do sistema de tipos, elas
nunca incluem nenhum código de implementação e não geram código na
compilação.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Por exemplo, se você quisesse escrever código no TypeScript que usasse o
jQuery, a função global “jQuery” precisaria ser de nida usando uma
declaração de ambiente. Na verdade, muitas declarações de ambiente para
várias bibliotecas JavaScript, incluindo jQuery, podem ser encontradas no
projeto De nitelyTyped. O jquery.d.ts de De nitelyTyped é assim:

// ...

(selector: string, context?: any): JQuery;


(element: Element): JQuery;
(object: {}): JQuery;
(elementArray: Element[]): JQuery;
(object: JQuery): JQuery;
(func: Function): JQuery;
(): JQuery;

// ...
}

declare let jQuery: JQueryStatic;


declare let $: JQueryStatic;

Como as declarações de ambiente não geram código, elas normalmente são


colocadas em arquivos com uma extensão de .d.ts . Qualquer arquivo que

termina em .d.ts ao invés de .ts não vai gerar um módulo compilado

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
correspondente, assim, essa extensão de arquivo também pode ser útil para
os módulos normais do TypeScript que contêm apenas de nições de
interface.

Conforme mencionado anteriormente quando discutimos importações e


exportações, os módulos também podem ser de nidos como declarações de
ambiente, o que torna possível consumir o código JavaScript que já está
adequadamente modularizado, como o Dojo Toolkit:

declare module 'dojo/_base/array' {


let array: {
every<T>(array: T[], callback: (value: T, index: number, array:
T[]) => boolean, thisArg?: any): boolean;
filter<T>(array: T[], callback: (value: T, index: number, array:
T[]) => boolean, thisArg?: any): T[];
forEach<T>(array: T[], callback: (value: T, index: number, array:
T[]) => void, thisArg?: any): void;
indexOf<T>(array: T[], value: T, fromIndex?: number, findLast?:
boolean): number;
lastIndexOf<T>(array: T[], value: T, fromIndex?: number): number;
map<T>(array: T[], callback: (value: T, index: number, array:
T[]) => T, thisArg?: any): T[];
some<T>(array: T[], callback: (value: T, index: number, array:
T[]) => boolean, thisArg?: any): boolean;
};
export = array;
}

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Quando você está escrevendo um código TypeScript que precisa acessar as
declarações de ambiente, um comentário de referência especial deve ser
adicionado ao topo do módulo que precisa dele:

/// <reference path="jquery" />

O caminho fornecido no comentário de referência pode ser um ID de


módulo padrão ou um caminho para um arquivo. Se você usar um caminho
do sistema de arquivos e obter um erro sobre o fato de o TypeScript não
conseguir resolver o caminho, certi que-se de não ter digitado
acidentalmente .ts como .js .

Ao escrever um código modular, os comentários de referência só devem ser


usados para importar declarações de ambiente; Todas as outras
dependências devem ser carregadas usando a palavra-chave import .

Felizmente, as dependências carregadas via import que nunca são usadas,


ou que são usadas apenas para veri cações em tempo de compilação, serão
inteligentemente excluídas na saída do compilador.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Carregador de Plugins
Se você é um usuário AMD, provavelmente estará acostumado a trabalhar
com um carregador de plugins ( text! e a ns). O TypeScript não suporta
import desses tipos de módulos dinâmicos automaticamente, mas possui
um mecanismo para habilitar seu uso.

Para usar um plugin do AMD, você precisará usar a diretiva <amd-

dependency> . No TypeScript 1.4 e anterior, um hipotético uso de um plugin

text! é semelhante ao seguinte:

/// <amd-dependency path="text!foo.html" />


declare let require: (moduleId: string) => any;
const foo: string = require('text!foo.html');

Existe um atributo name para a diretiva que facilita o uso de plugins AMD:

/// <amd-dependency path="text!foo.html" name="foo" />


declare let foo: string;

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
O TypeScript 2.0+ simpli cou bastante isso através da adição de módulos
wildcard. Para suportar carregadores de plugins de módulos no AMD ou
SystemJS, é necessário ser capaz de digitar o módulo, com o entendimento
de que o nome do módulo é variável através do parâmetro que é passado
para o plugin. Por exemplo, isso possibilita suportar o carregamento de
arquivos HTML, JSON e outros recursos com mais exibilidade.

declare module "json!*" {


let json: any;
export default json;
}

import d from "json!a/b/bar.json";


// lookup:
// json!a/b/bar.json
// json!*

React e suporte ao JSX


Diversas melhorias foram feitas ao longo dos anos para o TypeScript
melhorar o suporte à sintaxe JSX que é popularizada pelo React. Mais
informações podem ser encontradas na documentação do suporte ao JSX.

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Análise de controle de uxo
A análise de controle de uxo ajuda a detectar e evitar erros comuns. Alguns
exemplos adicionados de recursos de análise incluem: código inacessível,
parâmetros não utilizados, retornos implícitos, fall-throughs de declarações
case , restrição e ampliação de tipos alinhados com a lógica do seu código,

veri cação rígida de nulos e restrição literal de string e número em


igualdade e melhor inferência para tipos literais. Muitas dessas mudanças
podem ser substituídas com bandeiras do compilador, como --

allowUnreachableCode , --allowUnusedLabels , --noImplicitReturns , --

noImplicitAny , --noFallthroughCasesInSwitch , --strictNullChecks , etc.

Conclusão
Nosso artigo avançado sobre o TypeScript explora mais sobre como usar o
sistema de classes do TypeScript e também explora alguns recursos
avançados, como símbolos e decoradores.

Como o TypeScript continua evoluindo, ele traz consigo não apenas


tipagem estática, mas também novos recursos das especi cações atuais e
futuras do ECMAScript. Isso signi ca que você pode começar a usar o
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
TypeScript com segurança hoje, sem se preocupar com a necessidade de
reformular o código em alguns meses, ou se precisará alternar para um
novo compilador para aproveitar os melhores e mais recentes recursos de
idioma. Alterações de introduzem alguma quebra de sintaxe, são
documentadas no wiki TypeScript.

Se você quiser obter mais detalhes sobre qualquer um dos recursos descritos
neste guia, a Especi cação da linguagem TypeScript é a fonte da linguagem.
O Stack Over ow também é um excelente lugar para discutir sobre o
TypeScript e fazer perguntas, e o Manual do TypeScript também pode
fornecer algumas informações adicionais além do que este guia fornece.

Continuando sua aprendizagem


Acreditamos que é mais importante do que nunca aprender os fundamentos
do ES2015+ e do TypeScript. Com as primeiras mudanças substanciais no
idioma em quase 20 anos, agora é a hora de aprender como aproveitar
e cientemente essas alterações em nossa linguagem principal para a criação
de aplicativos da Web. SitePen tem o prazer de fornecer a você ou sua

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
empresa consultoria para desenvolver sua próxima aplicação; basta nos
enviar um email para começar!

⭐ Créditos
The De nitive TypeScript Guide, escrito originalmente por Nick Nisi no
blog do SitePen

Typescript JavaScript Front End Development Web Development Programming

839 claps

WRITTEN BY

Eduardo Rabelo Follow

☕🇳🇿 - https://eduardorabelo.me

See responses (1)

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
More From Medium

Related reads

App development with React Native.


Tresor Cyubahiro
79
Sep 17, 2018 · 7 min read

Related reads

6: Web App!

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Christian Grewell in applab
234
Oct 16, 2018 · 3 min read

Related reads

Introduction To Flutter.io: Overview


Austin Howard Tech
257
Nov 16, 2018 · 3 min read

Discover Medium Make Medium yours Become a member


Welcome to a place where words matter. Follow all the topics you care about, and Get unlimited access to the best stories
On Medium, smart voices and original we’ll deliver the best stories for you to on Medium — and support writers while

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
ideas take center stage - with no ads in your homepage and inbox. Explore you’re at it. Just $5/month. Upgrade
sight. Watch

About Help Legal

Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD

Você também pode gostar