String vs string no TypeScript: qual escolher para performance?

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

String vs string: o assassino silencioso da performance do seu código

\n\n

Você já se perguntou por que o TypeScript reclama de String em um lugar e de string em outro? Ou talvez já tenha visto desenvolvedores experientes torcerem o nariz ao ver new String("hello")? Essa é uma dúvida clássica no Stack Overflow, com milhares de visualizações. E não é à toa. A diferença entre String e string não é apenas uma peculiaridade da linguagem, mas uma distinção fundamental que impacta a performance, a segurança e a legibilidade do seu código.

\n\n

Neste artigo, não vamos apenas dar uma definição superficial. Vamos explorar o que está por trás de cada um desses tipos, como eles se comportam em tempo de execução e por que a escolha certa pode acelerar sua aplicação em dezenas de por cento. Prepare-se, vai ser interessante!

\n\n

Primitivos vs Objetos: o básico dos básicos

\n\n

Para entender a diferença, precisamos lembrar como o JavaScript (e, por consequência, o TypeScript) lida com dados. A linguagem tem dois tipos de valores:

\n\n
    \n
  • Primitivos (primitives): string, number, boolean, null, undefined, symbol, bigint. Eles são imutáveis e armazenados por valor.
  • \n
  • Objetos (objects): Object, Array, Function, além de String (com letra maiúscula), Number, Boolean. Eles são mutáveis e armazenados por referência.
  • \n
\n\n

Quando você escreve let nome: string = "Alice", você cria um primitivo. Quando escreve let nome: String = new String("Alice"), você cria um objeto wrapper. E é aí que a coisa fica interessante.

\n\n

Tipo string (com letra minúscula)

\n

Este é o tipo primitivo. É usado em 99,9% dos casos. É leve, rápido e previsível. A comparação de dois primitivos é feita por valor:

\n\n
let a: string = "hello";\nlet b: string = "hello";\nconsole.log(a === b); // true
\n\n

O TypeScript recomenda usar exatamente este. É o padrão de facto para declarar variáveis de string, parâmetros de funções e valores de retorno.

\n\n

Tipo String (com letra maiúscula)

\n

Este é o tipo objeto, um construtor wrapper. Ele existe desde os primórdios do JavaScript para trabalhar com métodos de string. No entanto, seu uso direto é considerado um antipadrão, a menos que você tenha uma tarefa muito específica. A comparação de dois objetos String é feita por referência:

\n\n
let a: String = new String("hello");\nlet b: String = new String("hello");\nconsole.log(a === b); // false! São objetos diferentes na memória
\n\n

Isso pode levar a bugs difíceis de encontrar. Imagine verificar se o valor de uma string é "hello" e receber false só porque alguém usou new String().

\n\n

Performance: por que string vence?

\n\n

Agora vamos ao que interessa: números e otimização. Vamos escrever um teste de performance simples (você pode executá-lo no seu ambiente, como Node.js ou no navegador).

\n\n
// Teste de performance\nconst iteracoes = 1_000_000;\n\nconsole.time("string (primitivo)");\nlet soma = "";\nfor (let i = 0; i < iteracoes; i++) {\n    soma += "a";\n}\nconsole.timeEnd("string (primitivo)");\n\nconsole.time("String (objeto)");\nlet somaObj = new String("");\nfor (let i = 0; i < iteracoes; i++) {\n    somaObj += "a"; // Aqui ocorre autoboxing e unboxing\n}\nconsole.timeEnd("String (objeto)");
\n\n

O resultado em uma máquina típica será drasticamente diferente (a favor do primitivo de 2 a 5 vezes). Por quê? Porque:

\n
    \n
  • Primitivo string — é apenas uma sequência de caracteres na memória. As operações com ele são otimizadas no nível do motor JavaScript.
  • \n

Blogs

Book Recommendations