ProgramaciónDesarrollador Fullstack

¿Cómo funciona el mecanismo de Campos Privados (propiedades privadas) en las clases de TypeScript? ¿Cuáles son las diferencias entre las propiedades privadas utilizando el modificador private y el símbolo #, cuáles son las particularidades de su uso y limitaciones?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Historia de la cuestión

En TypeScript, las propiedades privadas aparecieron inicialmente a través del modificador private, y desde ECMAScript 2021, JavaScript soporta campos verdaderamente privados mediante el símbolo #. El objetivo principal es la encapsulación de datos, para proteger los detalles internos de la clase del acceso externo.

Problema

El modificador private en TypeScript proporciona la privacidad solo en el momento de la compilación, pero en el JavaScript compilado, estos campos permanecen accesibles a través del acceso directo a las propiedades del objeto. Esto puede llevar a un cambio involuntario del estado del objeto. Los Campos Privados de ES (#) son completamente inaccesibles fuera de la clase incluso a nivel de ejecución de JS, lo que proporciona una verdadera protección de los datos.

Solución

TypeScript soporta ambos enfoques. Al elegir entre ellos, guíese por el grado necesario de protección y las limitaciones de compatibilidad con las versiones de JS.

Ejemplo de código:

class Example { private hidden: number; #trulyHidden: string; constructor() { this.hidden = 42; this.#trulyHidden = 'secret'; } getHidden() { return this.hidden; } getTrulyHidden() { return this.#trulyHidden; } } const x = new Example(); // x.hidden — error en TS, pero funcionará a través de x['hidden'] en JS // x.#trulyHidden — error de sintaxis incluso en JS

Características clave:

  • private garantiza la privacidad solo en la etapa de compilación de TypeScript
  • #field proporciona una verdadera privacidad a nivel de ejecución de JavaScript
  • El uso de # requiere soporte para JS moderno (ES2021+)

Preguntas trampa.

¿Se puede acceder a un campo privado de una clase TypeScript a través de un acceso directo en JS?

Sí, se puede, ya que la privacidad se implementa solo en la etapa de compilación. En el JS original, el campo será una propiedad normal del objeto. Por ejemplo:

class A { private x = 1; } const a = new A(); console.log((a as any)["x"]); // 1

¿Se pueden usar campos privados con # en interfaces o describirlos usando type?

No, los campos #private son parte solo de la implementación de la clase y no pueden ser descritos en interfaces, tipos o ser usados fuera de la misma clase. Las interfaces describen solo miembros públicos.

¿Se pueden heredar campos privados declarados con #?

No, tales campos no están disponibles para las clases hijas en absoluto. Solo la clase misma tiene acceso a ellos:

class Parent { #foo = 123; } class Child extends Parent { // this.#foo = 444; // Error }

Errores comunes y anti-patterns

  • Usar private para proteger datos críticos — conduce a vulnerabilidades por acceso directo
  • Confusión entre privacidad a nivel de tipos y de ejecución
  • Intentar usar #fields en versiones antiguas de JS

Ejemplo de la vida real

Caso negativo

En un proyecto para almacenar contraseñas, se utilizó el campo private password en la clase User. Uno de los desarrolladores accidentalmente accede a través de user['password'] para depurar, y el campo es modificado por un módulo externo.

Pros:

  • Integración simple con TypeScript

Contras:

  • No hay verdadera protección en tiempo de ejecución de JS
  • Es fácil eludir la privacidad accidentalmente

Caso positivo

Un desarrollador utiliza el campo privado de ES #password. Ahora los intentos de acceder al campo a través de indexación o en herederos no tienen éxito, la seguridad de los datos está asegurada incluso al usar bibliotecas y herramientas externas.

Pros:

  • Verdadera privacidad
  • Protección confiable de propiedades sensibles

Contras:

  • Requiere soporte para JS moderno (no compatible con ES5)
  • Los campos privados no son visibles en interfaces, no se pueden redefinir en herederos