Estoy tratando de implementar una interfaz en una clase como esta:
type TLanguage = "TYPE" | "SCRIPT" // Reusable values interface AnyInterface { business: TLanguage /** MoreTypes */ } class Anyclass implements AnyInterface{ business = "TYPE" }
Esto arroja un error:
La propiedad 'negocio' en el tipo 'Anyclass' no se puede asignar a la misma propiedad en el tipo base 'AnyInterface'. El tipo 'cadena' no se puede asignar al tipo 'TLanguage'.ts(2416)
El comportamiento esperado es que cada vez que establezca cualquier valor de negocio fuera del alcance de TLanguage, arrojaría un error... Funciona cuando lo configuro en una variable:
const anyConst: AnyInterface = { business: "TYPE" //✅ business: "TYPEs" //❌ Type '"TYPEs"' is not assignable to type 'TLanguage'. Did you mean '"TYPE"'?ts(2820) }
Cuando una clase implements
una interfaz , en realidad no afecta el tipo de clase. El compilador verifica que la clase sea compatible con la interfaz, pero no usa la interfaz como contexto para dar tipos a los miembros de la clase. Este es un punto doloroso en TypeScript, ya que las personas esperan que suceda algún tipo de inferencia contextual. Consulte microsoft/TypeScript n.° 32082 y los problemas relacionados para obtener más información.
Cuando escribes class Anyclass implements AnyInterface {...}
, el compilador actúa de manera muy similar a como si acabaras de escribir class Anyclass {...}
sin implements AnyInterface
. Si lo implementa incorrectamente (o si el compilador lo infiere), obtendrá un error en el nombre de Anyclass
.
Por lo tanto, el problema es que la class Anyclass { business = "TYPE" }
hace que business
se amplíe automáticamente del tipo literal "TYPE"
a string
, ya que el compilador no tiene contexto para hacer lo contrario, e implements AnyInterface
no cambia esto.
Y esto también significa que sus soluciones aquí son las mismas que tendría que usar si no implements AnyInterface
. Podría anotar explícitamente el tipo del campo :
class Anyclass implements AnyInterface { business: TLanguage = "TYPE" }
o podría usar una aserción const
para pedirle al compilador que no amplíe el literal de la cadena (pero esto inferirá "TYPE"
y no TLanguage
para el tipo de propiedad):
class Anyclass implements AnyInterface { business = "TYPE" as const // (property) Anyclass2.business: "TYPE" }
o podría convertirlo en una propiedad de readonly
que también sugiere que el compilador no se amplíe (por lo que es "TYPE"
) y tampoco le permitirá reasignarlo:
class Anyclass implements AnyInterface { readonly business = "TYPE" // (property) Anyclass3.business: "TYPE" }
Puedes arreglar esto con as const
:
type TLanguage = "TYPE" | "SCRIPT" interface AnyInterface { business: TLanguage /** MoreTypes */ } class Anyclass implements AnyInterface{ business = "TYPE" as const }