Búsqueda de sitios web

javascript - La clase TypeScript que implementa una interfaz con un campo de tipo unión resulta en un error (2322)


No entiendo por qué ocurre el error 2322.

Por favor, examine el siguiente fragmento de código:

interface Fish {
  alive: string | boolean;
}

class FishClass implements Fish {
  alive  = 'Yes'

  constructor() {
    // Type 'boolean' is not assignable to type 'string'.(2322)
    this.alive = true; 
  }
}

La interfaz define el tipo unión para string | boolean.

¿Por qué el tipo se fija cuando asigné uno de los dos tipos posibles al campo dentro de la clase que implementa la interfaz?

Respuesta #1

A pesar de las expectativas de la mayoría de las personas, los miembros de una clase no se tipan contextualmente según los tipos que se declaran para implementar o extender. Una declaración de extends o implements en una clase no tiene ningún efecto en absoluto sobre el tipo de la instancia de la clase. En cambio, solo realiza una verificación de la clase con respecto a la superclase o interfaz después del hecho. Así que si tu clase no logra implementar o extender lo que has declarado, recibirás una advertencia del compilador. Pero en lo que respecta a los tipos resultantes, será lo mismo que si eliminaras la cláusula extends o implements por completo. No, a nadie le gusta esto.

Consulta microsoft/TypeScript#3667 para la solicitud original de corregir esto, y hubo un intento en microsoft/TypeScript#6118 pero finalmente se abandonó debido a algunos problemas con bibliotecas existentes; consulta este comentario. Hay varios problemas abiertos sobre esto, incluyendo microsoft/TypeScript#32082; si quieres que esto se resuelva, podrías ir a ese problema y darle un 👍, pero por ahora solo tenemos que vivir con el hecho de que class Foo implements Bar {/*...*/} tiene las mismas implicaciones para el tipo de Foo que class Foo {/*...*/}.


En tu caso, eso significa que class FishClass implements Fish {/*...*/} actúa exactamente como class FishClass {/*...*/} en lo que respecta a cómo se infieren los miembros. Dado que la propiedad alive se inicializa con un valor string de "Yes", el compilador la infiere como de tipo string. Y más adelante, cuando asignas true a ella, eso es un error porque no puedes asignar un boolean a un string. Ten en cuenta que string es asignable a string | boolean, por lo que la verificación de FishClass implements Fish tiene éxito; se te permite restringir las propiedades de los subtipos.

La forma correcta de manejar esto por ahora es anotar manualmente el campo con el tipo deseado:

class FishClass implements Fish {
   alive: string | boolean = 'Yes'; // okay

   constructor() {
      this.alive = true; // okay
   }
}

Enlace de Playground al código