ProgramaciónDesarrollador Frontend

¿Cómo funciona el mecanismo de tipado de `this` en los métodos de las clases de TypeScript al usar funciones normales y funciones flecha? Describe las trampas y las mejores prácticas.

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

En TypeScript, para los métodos dentro de una clase, el tipo de this por defecto es la instancia actual de la clase. Sin embargo, si se definen los métodos como funciones flecha, el contexto de this estará ligado al momento de la declaración, no al de la invocación.

Método normal:

class Counter { value = 0; increment() { this.value++; } }

Función flecha:

class Counter { value = 0; increment = () => { this.value++; } }

Particularidades:

  • Los métodos normales pierden el contexto de this cuando se pasan como callbacks (por ejemplo, en listeners de eventos).
  • Las flechas mantienen el contexto de la clase declarada, pero no son visibles en el prototipo y se crean para cada instancia.
  • Se puede especificar explícitamente el tipo de this en la firma del método para una verificación adicional:
class Foo { bar(this: Foo) { // ... } }

Pregunta capciosa.

¿Cuál es la diferencia entre increment() y increment = () => {} en una clase? ¿Cómo afecta esto al contexto de this cuando se usa como callback?

Respuesta incorrecta:

  • "No hay diferencia entre el campo de la clase y el método, TypeScript lo entiende todo."

Respuesta correcta:

  • En el método normal, el contexto de this se define en el momento de la invocación. Si se pasa el método como función: setTimeout(counter.increment, 0), entonces this será undefined (en modo estricto) o window (en modo no estricto), mientras que la función flecha mantendrá su entorno:
class Demo { value = 1; inc() { console.log(this.value); } incArrow = () => { console.log(this.value); } } const d = new Demo(); setTimeout(d.inc, 0); // undefined o error setTimeout(d.incArrow, 0); // 1

Ejemplos de errores reales debido al desconocimiento de las sutilezas del tema.


Historia

En un proyecto con frameworks reactivos, se pasaron los métodos de clase directamente como callbacks sin un bind explícito. Como resultado, this se volvió undefined, y la aplicación fallaba con un error al acceder a las propiedades de this. Se resolvió el problema reescribiendo los métodos como funciones flecha o usando un bind explícito.


Historia

Un desarrollador especificó explícitamente el tipo de this en el método, pero olvidó la tipificación dentro de la función flecha dentro de ese método. Como resultado, this dentro del callback anidado no apuntaba a la instancia de la clase, sino a window. El equipo se enfrentó a una fuga de estado, y se tuvo que rehacer la arquitectura de eventos.


Historia

Un gran componente de UI ralentizaba la aplicación, porque todos los métodos se habían descrito como campos flecha de la clase (new Counter().increment = ...), lo que creaba nuevas copias de funciones para cada instancia, en lugar de una única definición en el prototipo, como sucede con el método normal. Como resultado, aumentó el consumo de memoria y se necesitó una optimización.