typescript - ¿Cuál es la diferencia entre readonly y la afirmación const para las propiedades de clase?
¿Alguien podría aclararme cuál es la diferencia entre las dos siguientes notaciones en TypeScript?
class Test {
readonly ANSWER = 42;
}
y
class Test {
ANSWER = 42 as const;
}
El primero es un modificador readonly, mientras que el segundo se llama const assertion. Ambos conceptos están bien documentados y explicados en varios lugares, sin embargo, a mí me parece que ambos hacen lo mismo, al menos en este caso simple, es decir, hacer que la propiedad sea inmutable. Incluso su combinación parece ser válida:
class Test {
readonly ANSWER = 42 as const;
}
Entonces, ¿por qué se permite la sintaxis de ambos y hay alguna ventaja o desventaja en usar uno sobre el otro?
Para aclarar más: Estoy completamente consciente de la diferencia entre const regular y readonly. Estoy específicamente interesado en la diferencia entre la afirmación const y readonly.
Respuesta #1
readonly ANSWER=42 describe la asignabilidad de una propiedad. TypeScript es lo suficientemente inteligente para saber que ningún otro valor puede ser asignado, por lo que es seguro inferir un tipo lo más específico posible. En este caso 42 en lugar de number
Donde ANSWER=42 as const describe el tipo de un valor y fuerza una inferencia constante del tipo, en lugar del valor predeterminado de number.
Son cosas muy diferentes.
Aquí hay un mejor ejemplo:
class Test1 {
ANSWER = 42 as const;
set42() {
this.ANSWER = 42 // fine
}
}
class Test2 {
readonly ANSWER = 42;
set42() {
this.ANSWER = 42 // error
}
}
Aquí Test1's ANSWER tiene un tipo de valor del literal numérico 42. Puedes asignar lo que quieras a esa propiedad mientras sea 42. Sin as const el tipo se inferiría como number en su lugar, y permitiría asignar cualquier número.
Sin embargo, ANSWER de Test2 no puede reasignarse, incluso si es del tipo correcto, porque es readonly.
Parque infantil
La diferencia es más evidente con tipos más complejos:
class Test1 {
obj = { a: 123 } as const;
// Test1.obj: { readonly a: 123; }
setObj() {
this.obj = { a: 123 } // fine
}
setObjProp() {
this.obj.a = 456 // error
}
}
class Test2 {
readonly obj = { a: 123 };
// Test2.obj: { a: number; }
setObj() {
this.obj = { a: 123 } // error
}
setObjProp() {
this.obj.a = 456 // fine
}
}
class Test3 {
readonly obj = { a: 123 } as const;
// Test3.obj: { readonly a: 123; }
setObj() {
this.obj = { a: 123 } // error
}
setObjProp() {
this.obj.a = 123 // error
}
}
Aquí, el modificador readonly en Test2 no logra inferir el tipo más específico de { a: 123 } y en su lugar vuelve a { a : number }.
Pero mientras que la propiedad Test2.obj es de solo lectura, el objeto asignado a ella sigue siendo mutable. Así que this.obj.a=456 es válido, y por eso { a: number } es el tipo inferido.
Donde con as const el objeto en sí es de solo lectura, por lo que no se puede modificar.
Cuando combinas tanto readonly como as const, declaras una propiedad inmutable con un valor que también es inmutable.
Parque infantil
