Narrow Types com `const` modifier
Podemos limitar a tipagem de TS para receber tipos mais estreitos ("narrow types"). Por exemplo, como essa variável é uma const, o TS já declara ela do tipo literal ao invés de um tipo abrangente como string
const example = "hello world";
// ^? const example: "hello world"Só que quando a gente vai passando valores pra lá e pra cá, alguns desses tipos podem acabar ficando mais abrangentes, o que geralmente não é desejado. Por exemplo, se eu passar para uma função que recebe e retorna string, o tipo mais estreito vai se perder no meio do caminho.
const returnString = (s: string) => s;
const example = returnString('Hello world');
// ^? const example: stringCom a ajuda de generics, podemos manter o tipo mais estreito
const returnString = <TString extends string>(s: TString) => s;
const example = returnString('Hello world');
// ^? const example: 'Hello world'Isso não funciona com tipagens mais complexas. Se eu tentar fazer isso com um array de strings, o array é mutável por padrão, e não tem como TS perceber isso de antemão.
const returnArray = <TArray extends string[]>(arr: TArray) => arr;
const example = returnArray(['alice', 'bob', 'charles']);
// ^? const example: string[]Nesses casos, era costume de desenvolvimento colocar um as const depois do valor. Isso anuncia pro TS que esse array não é mutável e ele consegue retornar a tipagem original.
const example = returnArray(['alice', 'bob', 'charles'] as const);
// ^? const example: ['alice', 'bob', 'charles']Mas isso não é o suficiente. Quem vai chamar a função precisa lembrar de colocar as const, e isso torna o código refém de erros humanos. Também, já que toda vez que função for executada precisa passa as const, o código fica mais verboso, ainda mais se a função é chamada muitas vezes pelo projeto. Essas falhas ficam bem pronunciadas para bibliotecas, já que o criador da API tem que educar os usuários da biblioteca a usar o as const.
No TS v5.0, chega então o modificador const de tipos genéricos
const returnArray = <const TArray extends string[]>(arr: TArray) => arr;
const example = returnArray(['alice', 'bob', 'charles']);
// ^? const example: ['alice', 'bob', 'charles']Com o modificador const antes da declaração do parâmetro TArray, a função usa o valor que é passado para ela como se o argumento utilizasse as const.