O TypeScript 5.4 e 5.5 trouxeram melhorias na inferência de tipos, aprimoramentos de performance e novos tipos utilitários. Neste artigo, explicamos essas novas funcionalidades com exemplos práticos de código.
Novas Funcionalidades do TypeScript 5.4
Tipo Utilitário NoInfer
NoInfer<T> é um novo tipo utilitário que suprime a inferência de parâmetros de tipo.
// NoInfer - Controle de inferência de tipos
// Problema: Inferência de tipo não intencional
function createState<T>(initial: T, allowed: T[]): T {
return allowed.includes(initial) ? initial : allowed[0];
}
// Inferido como string ao invés de "red" | "blue"
const state1 = createState("red", ["red", "blue", "green"]);
// Solução com NoInfer
function createStateFixed<T>(initial: T, allowed: NoInfer<T>[]): T {
return allowed.includes(initial) ? initial : allowed[0];
}
// Inferido corretamente como "red" | "blue" | "green"
const state2 = createStateFixed("red", ["red", "blue", "green"]);
// Exemplo prático: Event Handler
type EventMap = {
click: { x: number; y: number };
keypress: { key: string };
scroll: { scrollY: number };
};
function addEventListener<K extends keyof EventMap>(
event: K,
handler: (data: NoInfer<EventMap[K]>) => void
): void {
// implementação
}
// O tipo do handler não é inferido a partir de EventMap[K]
addEventListener("click", (data) => {
// data é corretamente tipado como { x: number; y: number }
console.log(data.x, data.y);
});
Melhoria no Narrowing Dentro de Closures
O narrowing de tipos dentro de funções e callbacks foi significativamente melhorado.
// Narrowing melhorado dentro de closures
function processData(value: string | number | null) {
// TypeScript 5.3 e anteriores: Narrowing perdido dentro do callback
// TypeScript 5.4: Narrowing mantido
if (value === null) {
return;
}
// Aqui value é string | number
const handlers = {
// TS 5.4: Narrowing mantido dentro da closure
process: () => {
// value é reconhecido como string | number
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
},
log: () => {
// Narrowing mantido aqui também
console.log(value);
}
};
return handlers.process();
}
// Narrowing após condicionais
function example(arr: string[] | null) {
if (arr === null) {
return;
}
// TypeScript 5.4: arr é string[] dentro do callback do map
arr.map((item) => {
// Garantido que arr não é null
console.log(arr.length); // OK
return item.toUpperCase();
});
}
// Exemplo mais complexo
type Result<T> = { success: true; data: T } | { success: false; error: string };
function processResult<T>(result: Result<T>) {
if (!result.success) {
return null;
}
// result.data está disponível
const transformers = {
// Reconhecido dentro da closure que result.success é true
transform: () => {
return result.data; // TS 5.4: OK
}
};
return transformers.transform();
}
Suporte a Tipos para Object.groupBy
Suporte a tipos foi adicionado para Object.groupBy e Map.groupBy do ES2024.
// Object.groupBy - Compatível com ES2024
interface User {
id: string;
name: string;
role: 'admin' | 'user' | 'guest';
department: string;
}
const users: User[] = [
{ id: '1', name: 'Alice', role: 'admin', department: 'Engineering' },
{ id: '2', name: 'Bob', role: 'user', department: 'Engineering' },
{ id: '3', name: 'Charlie', role: 'user', department: 'Sales' },
{ id: '4', name: 'Diana', role: 'guest', department: 'Marketing' },
];
// Agrupar por role
const byRole = Object.groupBy(users, (user) => user.role);
// Tipo: Partial<Record<'admin' | 'user' | 'guest', User[]>>
console.log(byRole.admin); // [{ id: '1', name: 'Alice', ... }]
console.log(byRole.user); // [{ id: '2', ... }, { id: '3', ... }]
// Agrupar por department
const byDepartment = Object.groupBy(users, (user) => user.department);
// Tipo: Partial<Record<string, User[]>>
// Map.groupBy - Retorna um Map
const byRoleMap = Map.groupBy(users, (user) => user.role);
// Tipo: Map<'admin' | 'user' | 'guest', User[]>
byRoleMap.forEach((users, role) => {
console.log(`${role}: ${users.length} users`);
});
// Exemplo prático: Agrupar por data
interface Order {
id: string;
amount: number;
date: Date;
}
function groupOrdersByMonth(orders: Order[]) {
return Object.groupBy(orders, (order) => {
const month = order.date.toISOString().slice(0, 7); // "2025-12"
return month;
});
}
Novas Funcionalidades do TypeScript 5.5
Type Predicates Inferidos
Os type guards agora são automaticamente inferidos a partir do valor de retorno da função.
// Type Predicates Inferidos
// TS 5.4 e anteriores: Type predicate explícito necessário
function isStringOld(value: unknown): value is string {
return typeof value === 'string';
}
// TS 5.5: Type predicate inferido automaticamente
function isString(value: unknown) {
return typeof value === 'string';
}
// Tipo inferido: (value: unknown) => value is string
// Uso com filter de arrays
const mixed: (string | number | null)[] = ['a', 1, null, 'b', 2];
// TS 5.4 e anteriores: Resultado do filter permanece (string | number | null)[]
const stringsOld = mixed.filter((x): x is string => typeof x === 'string');
// TS 5.5: Automaticamente inferido como string[]
const strings = mixed.filter((x) => typeof x === 'string');
// Tipo: string[]
// Remoção de null também automática
const notNull = mixed.filter((x) => x !== null);
// Tipo: (string | number)[]
// Exemplo complexo
interface User {
id: string;
name: string;
email?: string;
}
const users: (User | null)[] = [
{ id: '1', name: 'Alice', email: 'alice@example.com' },
null,
{ id: '2', name: 'Bob' },
];
// Tipo automaticamente refinado
const validUsers = users.filter((user) => user !== null && user.email);
// Tipo: User[] (apenas usuários com email)
Verificação de Sintaxe de Expressões Regulares
Verificação de sintaxe foi adicionada para literais de expressões regulares.
// Verificação de sintaxe de expressões regulares
// TS 5.5: Expressões regulares inválidas geram erro de compilação
// Erro: Sequência de escape inválida
// const invalid1 = /\p/;
// Erro: Classe de caracteres incompleta
// const invalid2 = /[a-/;
// Erro: Quantificador inválido
// const invalid3 = /a{}/;
// Expressões regulares válidas
const email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phone = /^\d{3}-\d{4}-\d{4}$/;
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
// Escape de propriedades Unicode (requer flag u)
const japanese = /\p{Script=Hiragana}+/u;
const emoji = /\p{Emoji}/u;
// Grupos de captura nomeados
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2025-12-02'.match(datePattern);
if (match?.groups) {
const { year, month, day } = match.groups;
console.log(year, month, day); // "2025", "01", "02"
}
Declarações Isoladas (Isolated Declarations)
A opção isolatedDeclarations permite acelerar a geração de declarações de tipo.
// tsconfig.json
{
"compilerOptions": {
"isolatedDeclarations": true,
"declaration": true
}
}
// Com isolatedDeclarations: true,
// é necessário explicitar tipos de retorno de funções e tipos de variáveis
// ❌ Erro: Tipo de retorno necessário
// export function add(a: number, b: number) {
// return a + b;
// }
// ✅ OK: Tipo de retorno explícito
export function add(a: number, b: number): number {
return a + b;
}
// ❌ Erro: Tipo da variável necessário
// export const config = { port: 3000, host: 'localhost' };
// ✅ OK: Tipo explícito
export const config: { port: number; host: string } = {
port: 3000,
host: 'localhost'
};
// Benefícios:
// - Possibilita paralelização do build
// - Gera .d.ts sem verificação de tipos
// - Build rápido em monorepos
Suporte a Tipos para Novos Métodos de Set
Suporte a tipos foi adicionado para métodos de Set do ES2024.
// Novos métodos de Set
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
// union: União
const union = setA.union(setB);
console.log([...union]); // [1, 2, 3, 4, 5, 6]
// intersection: Interseção
const intersection = setA.intersection(setB);
console.log([...intersection]); // [3, 4]
// difference: Diferença
const difference = setA.difference(setB);
console.log([...difference]); // [1, 2]
// symmetricDifference: Diferença Simétrica
const symmetricDiff = setA.symmetricDifference(setB);
console.log([...symmetricDiff]); // [1, 2, 5, 6]
// isSubsetOf: Verificação de subconjunto
const subset = new Set([2, 3]);
console.log(subset.isSubsetOf(setA)); // true
// isSupersetOf: Verificação de superconjunto
console.log(setA.isSupersetOf(subset)); // true
// isDisjointFrom: Verificação de disjunção
const setC = new Set([7, 8, 9]);
console.log(setA.isDisjointFrom(setC)); // true
// Exemplo prático: Filtragem por tags
interface Article {
id: string;
title: string;
tags: Set<string>;
}
function filterByTags(articles: Article[], requiredTags: Set<string>): Article[] {
return articles.filter(article =>
requiredTags.isSubsetOf(article.tags)
);
}
Melhorias de Performance
Aceleração da Verificação de Tipos
// Melhorias de performance do TypeScript 5.4/5.5
// 1. Verificação de tipos monomorfizada
// - Processamento acelerado para objetos com a mesma forma
// 2. Otimização de tipos condicionais
type IsString<T> = T extends string ? true : false;
// Cache interno melhorado
// 3. Otimização de build com referências de projeto
// tsconfig.json
{
"compilerOptions": {
"incremental": true,
"composite": true,
// Adicionado no 5.5
"isolatedDeclarations": true
},
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" }
]
}
// 4. Melhoria na responsividade do editor
// - Sugestões de auto-import aceleradas
// - Operações de refatoração melhoradas
Padrões de Tipos Práticos
Utilitários de Tipos Melhorados
// Padrões de tipos práticos
// 1. DeepPartial mais seguro
type DeepPartial<T> = T extends object
? { [P in keyof T]?: DeepPartial<T[P]> }
: T;
interface Config {
server: {
port: number;
host: string;
ssl: {
enabled: boolean;
cert: string;
};
};
database: {
url: string;
pool: number;
};
}
// Atualização parcial de configuração
function updateConfig(partial: DeepPartial<Config>): Config {
// Lógica de merge
return {} as Config;
}
updateConfig({
server: {
ssl: {
enabled: true
}
}
});
// 2. Sistema de eventos type-safe
type EventMap = {
'user:login': { userId: string; timestamp: Date };
'user:logout': { userId: string };
'order:created': { orderId: string; total: number };
};
class TypedEventEmitter<T extends Record<string, unknown>> {
private handlers = new Map<keyof T, Set<(data: any) => void>>();
on<K extends keyof T>(event: K, handler: (data: T[K]) => void): () => void {
if (!this.handlers.has(event)) {
this.handlers.set(event, new Set());
}
this.handlers.get(event)!.add(handler);
return () => this.handlers.get(event)?.delete(handler);
}
emit<K extends keyof T>(event: K, data: T[K]): void {
this.handlers.get(event)?.forEach(handler => handler(data));
}
}
const emitter = new TypedEventEmitter<EventMap>();
// Tratamento de eventos type-safe
emitter.on('user:login', (data) => {
// data é { userId: string; timestamp: Date }
console.log(data.userId, data.timestamp);
});
// 3. Propriedades condicionalmente obrigatórias
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>> &
{ [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>> }[Keys];
interface SearchParams {
query?: string;
categoryId?: string;
tags?: string[];
}
// Pelo menos uma condição de busca é obrigatória
type ValidSearchParams = RequireAtLeastOne<SearchParams, 'query' | 'categoryId' | 'tags'>;
function search(params: ValidSearchParams) {
// implementação
}
// OK
search({ query: 'test' });
search({ categoryId: '123' });
search({ query: 'test', tags: ['a', 'b'] });
// Erro
// search({}); // Pelo menos uma condição necessária
Guia de Migração
Migração de 5.3 para 5.4/5.5
# Upgrade
npm install typescript@latest
# Verificação de tipos
npx tsc --noEmit
# Correções comuns
// 1. Adaptação ao novo comportamento de narrowing
// Alguns códigos terão tipos inferidos corretamente,
// e asserções de tipo que eram necessárias antes podem não ser mais
// Antes (TS 5.3)
function example(value: string | null) {
if (value === null) return;
const fn = () => {
// value as string era necessário
return (value as string).toUpperCase();
};
}
// Depois (TS 5.4+)
function exampleNew(value: string | null) {
if (value === null) return;
const fn = () => {
// Asserção de tipo desnecessária
return value.toUpperCase();
};
}
// 2. Uso de Object.groupBy
// Verificação da configuração lib necessária
// tsconfig.json
{
"compilerOptions": {
"lib": ["ES2024"] // ou "ESNext"
}
}
Resumo
O TypeScript 5.4/5.5 trouxe melhorias significativas na inferência de tipos e performance.
Principais Novas Funcionalidades
| Funcionalidade | Versão | Impacto |
|---|---|---|
| NoInfer | 5.4 | Controle de inferência de tipos |
| Narrowing em closures | 5.4 | Melhoria na qualidade do código |
| Object.groupBy | 5.4 | Compatibilidade ES2024 |
| Type predicates inferidos | 5.5 | Melhoria no filter etc. |
| isolatedDeclarations | 5.5 | Aceleração do build |
| Verificação de regex | 5.5 | Detecção de erros aprimorada |
Recomendação de Upgrade
- Novos projetos: Adote a versão mais recente
- Projetos existentes: Migre gradualmente
- Projetos grandes: Utilize isolatedDeclarations
Com a evolução do TypeScript, é possível escrever código mais seguro e eficiente.