Javascript com tipos
Por que usar tipos no seu projeto Javascript
Javascript com tipos?
Centenas de linguagens foram desenhadas ou adaptadas para compilar para Javascript









Vamos focar nas duas que mantém a sintaxe original
Por que tipos estáticos?
Mais tipos, menos bugs

Mais tipos, menos testes
(ainda que um não substitua o outro)
Tipos são uma forma de documentação
Que funções esse módulo exporta?
Que parâmetros essa função recebe?
O que essa função retorna?
Contrato entre diferentes partes de uma aplicação
Exemplo: schema do GraphQL gerando tipos em Flow ou Typescript
Refatorar com confiança
E, se houver integração com ferramentas, de forma automática


As garotas da noite

Mantido pela Microsoft
Superset de Javascript
Prover funcionalidades do Javascript ainda planejadas hoje (ex: decorators, private instance methods, class fields) e não planejadas (Enum)
Transpilado
class Pessoa {
constructor(public cumprimento: string) {}
cumprimenta() {
return `<h1>${this.cumprimento}</h1>`;
}
};
var pessoa = new Pessoa("Ata");
pessoa.cumprimenta();
var Pessoa = /** @class */ (function () {
function Pessoa(cumprimento) {
this.cumprimento = cumprimento;
}
Pessoa.prototype.cumprimenta = function () {
return "<h1>" + this.cumprimento + "</h1>";
};
return Pessoa;
}());
var pessoa = new Pessoa("Ata");
pessoa.cumprimenta();
http://www.typescriptlang.org/play/
Tipagem estrutural
interface Square {
height: number;
width: number;
}
interface Rect {
height: number;
width: number;
}
let rect: Rect;
const square = {
width: 4,
height: 4
};
rect = square; // Ok

Mantido pelo Facebook
Uma extensão do Javascript
Não uma linguagem a parte
Apenas retira as anotações
/* @flow */
class Pessoa {
cumprimento: string;
constructor(cumprimento: string) {
this.cumprimento = cumprimento;
}
cumprimenta() {
return `<h1>${this.cumprimento}</h1>`;
}
}
const pessoa = new Pessoa('Ata');
pessoa.cumprimenta();
class Pessoa {
constructor(cumprimento: string) {
this.cumprimento = cumprimento;
}
cumprimenta() {
return `<h1>${this.cumprimento}</h1>`;
}
}
const pessoa = new Pessoa('Ata');
pessoa.cumprimenta();
https://flow.org/try/
Objetivos
- Ser preciso:
- Reportar todos os erros que possam ser detectados, sem falsos negativos
- Ser rápido:
- Não quebrar o ciclo do desenvolvedor de editar-atualizar
Inferência > anotações
Tipagem estrutural
(com tipos nominais também)
Objetivos em comum
Ser apenas Javascript™ com tipos estáticos
Adoção gradual com benefícios imediatos
Ser rápido, pra não travar o ciclo de edição e feedback dos desenvolvedores
Funcionalidades exclusivas
Non-null assertion
Typescript
const body = document.body; // HTMLElement | undefined
body.querySelector("nav"); // Erro
body!.querySelector("nav"); // Sem erro

Tipos opacos (ou nominais)
Flow
opaque type CPF = string;
opaque type RG = string;
function validateCpf(cpf: string): CPF | null {
if (isCpfValid(cpf)) return cpf;
else return null;
}
function validateRg(rg: string): RG | null { /*...*/ }
let myRg = validateRg(res.rg);
let myCpf = validateCpf(res.cpf);
myCpf = myRg; // Erro
myRg = myCpf; // Erro
Tipos condicionais e inferidos
Typescript
type Exclude<T, U> = T extends U ? never : T;
type NumberAlias = Exclude<string | number, number>;
type ReturnType<T extends Function> = T extends (...args: any[]) => infer R ? R : never;
type StringAlias = ReturnType<() => string>;
Tipo Existencial
Flow
type Entity = "Contact" | "Lawsuit";
type Map<K, V> = { [K]: V }
export const humanizeEntity: Map<Entity, *> = {
Contact: "Contato",
Lawsuit: "Processo",
};
Type guard
Typescript
interface Entity<Type extends string> {
type: Type;
name: string;
}
interface Organization extends Entity<"org"> {
location: string;
}
function isEntityOrganization(
entity: Entity<any>
): entity is Organization {
return entity.type === "org";
}
const entity: Entity<any> = { /*...*/ };
if (isEntityOrganization(entity) {
entity.location; // O tipo agora é Organization
}
Outras características e funcionalidades
Refatoração
- Exemplo: renomear variáveis e tipos
- É um foco do time do Typescript
- Integração de editores de texto e afins com Flow ainda é fraca


Geração de tipos por spec
- Exemplo: npm.im/graphql-code-generator
// schema.gql
type Organization {
title: String
id: Int!
}
// types.ts
export interface Organization {
title?: string | null;
id: number;
}
export type Resolver<Result, Parent = any, Context = any, Args = any> = (
parent: Parent,
args: Args,
context: Context,
info: GraphQLResolveInfo
) => Promise<Result> | Result;
export namespace OrganizationResolvers {
/* ... */
}
Ecossistema JS:
ESLint, Babel e afins
- Typescript exige ferramentas a parte, enquanto Flow é apenas Javascript
- Isso pode mudar com a implementação de Typescript do Babel ♥
Tipo de bibliotecas de terceiros
- Mais bibliotecas tem declaração de tipos em Typescript:
- flow-typed: ~500 bibliotecas
- definitely-typed: 5064 bibliotecas
- O processo de instalação e consumo é mais ergonômico em Typescript
- Declarações de tipo vem na própria lib, se seu package.json tiver o campo 'types'; ou o tipo é declarado a parte em pacote @types/lib
- Flow historicamente integra melhor com React (ex: defaultProps), mas Typescript implementou as features que faltavam
Plugins do Typescript
- Plugins permitem:
- Usar outra gramática dentro de tagged template literals:
- Exemplos de onde isso é útil:
- Relay: Relay.QL`fragment on Root { ... }`
- CSS in JS: styled.div` background-color: var(--primary); `
- Essas gramáticas permitem:
- Fazer highlight de sintaxe (e de erros de sintaxe)
- Autocomplete
- Exemplos de onde isso é útil:
- Criar novos refactorings para editores de texto
- Gerar valores a partir de tipos
- ts-transformer-keys: gera array de keys de um tipo
- Usar outra gramática dentro de tagged template literals:
Ergonomia / DX
- Ambos suportam tipos a partir de comentários, exigindo pouco esforço para uma adoção gradual
- Mas tipar com comentários duplica código, é menos legível e exige mais esforço
- Flow exige apenas um novo plugin no Babel (mas Typescript deve chegar lá também)
- Ambos tendem a consumir muita memória com o tempo
Inferência favorece agilidade

Flow
Como decidir?
Flow’s lighter-weight approach may suit dynamic-typing advocates better, whereas TypeScript’s DefinitelyTyped library and approach may perhaps be more appealing to strong-typing advocates coming from other languages.
O quanto tipar?
Nós já falamos disso

Mas não disso

É preciso achar o sweet spot

O seu sweet spot

Fonte: "Diminishing returns of static typing"

Happy hacking!
Javascript com tipos
By Victor Magalhães
Javascript com tipos
Por que usar tipos no seu projeto Javascript
- 789