String vs string en TypeScript: ¿cuál elegir para la velocidad?

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

String vs string: el asesino silencioso del rendimiento de tu código

\n\n

¿Alguna vez te has preguntado por qué en un lugar TypeScript se queja de String y en otro de string? ¿O quizás has visto cómo los desarrolladores experimentados se estremecen al ver new String("hola")? Esta pregunta es un verdadero éxito en Stack Overflow, con miles de visitas. Y no es casualidad. La diferencia entre String y string no es solo una peculiaridad del lenguaje, sino una diferencia fundamental que afecta el rendimiento, la seguridad y la legibilidad de tu código.

\n\n

En este artículo no solo daremos una definición seca. Analizaremos qué hay detrás de cada uno de estos tipos, cómo se comportan en tiempo de ejecución y por qué la elección correcta puede acelerar tu aplicación en decenas de porcentaje. ¡Prepárate, será interesante!

\n\n

Primitivos vs Objetos: conceptos básicos

\n\n

Para entender la diferencia, debemos recordar cómo JavaScript (y por lo tanto, TypeScript) trabaja con los datos. El lenguaje tiene dos tipos de valores:

\n\n
    \n
  • Primitivos: string, number, boolean, null, undefined, symbol, bigint. Son inmutables y se almacenan por valor.
  • \n
  • Objetos: Object, Array, Function, así como String (con mayúscula), Number, Boolean. Son mutables y se almacenan por referencia.
  • \n
\n\n

Cuando escribes let name: string = "Alice", creas un primitivo. Cuando escribes let name: String = new String("Alice"), creas un objeto envoltorio. Y aquí es donde comienza lo interesante.

\n\n

Tipo string (en minúscula)

\n

Este es un tipo primitivo. Se usa en el 99.9% de los casos. Es ligero, rápido y predecible. La comparación de dos primitivos se realiza por valor:

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

TypeScript recomienda usar este. Es el estándar de facto para declarar variables de cadena, parámetros de funciones y valores de retorno.

\n\n

Tipo String (con mayúscula)

\n

Este es un tipo objeto, un constructor envoltorio. Existe desde los tiempos de JavaScript para trabajar con métodos de cadenas. Sin embargo, su uso directo es más bien un antipatrón, a menos que tengas una tarea muy específica. La comparación de dos objetos String se realiza por referencia:

\n\n
let a: String = new String("hola");\nlet b: String = new String("hola");\nconsole.log(a === b); // false! Son objetos diferentes en memoria
\n\n

Esto puede provocar errores difíciles de detectar. Imagina que verificas si el valor de la cadena es "hola" y obtienes false solo porque alguien usó new String().

\n\n

Rendimiento: ¿por qué gana string?

\n\n

Ahora pasemos a lo más jugoso: los números y la optimización. Escribamos una prueba de rendimiento simple (puedes ejecutarla en tu entorno, por ejemplo, en Node.js o en el navegador).

\n\n
// Prueba de rendimiento\nconst iterations = 1_000_000;\n\nconsole.time("string (primitivo)");\nlet sum = "";\nfor (let i = 0; i < iterations; i++) {\n    sum += "a";\n}\nconsole.timeEnd("string (primitivo)");\n\nconsole.time("String (objeto)");\nlet sumObj = new String("");\nfor (let i = 0; i < iterations; i++) {\n    sumObj += "a"; // Aquí ocurre autoempaquetado y desempaquetado\n}\nconsole.timeEnd("String (objeto)");
\n\n

El resultado en una máquina típica será radicalmente diferente (a favor del primitivo de 2 a 5 veces). ¿Por qué? Porque:

\n
    \n
  • El primitivo string es simplemente una secuencia de caracteres en memoria. Las operaciones con él están optimizadas a nivel del motor.

Blogs

Book Recommendations