applyDamage un método applyDamage para aceptar number o string , pero lo implementé solo con un argumento number . Cuando llamo a este método usando la clase base, tengo un comportamiento incorrecto. ¿Por qué TypeScript no muestra un error?
interface Character { applyDamage(value : number): number; } interface Humanoid extends Character { hp:number; applyDamage(value: number|string): number } class Monster implements Humanoid { hp:number = 10; applyDamage(v: number) { this.hp -= v; return v; } } const monster:Humanoid = new Monster(); monster.applyDamage("hello"); console.log(monster.hp); // <-- NaNDefinió la firma del método en Humanoid para applyDamage para tomar un valor de entrada de string | number ;
TS solo verifica que su implementación para la clase Monster tenga la firma adecuada y devuelva el tipo definido. Depende de usted escribir un cuerpo de método que sea seguro.
Parece que tal vez quieras usar una sobrecarga. https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads
Como han señalado otros: una sobrecarga funcionaría... pero por la forma en que leo su código, parece que solo desea implementar un subtipo del parámetro de unión, por lo que creo que los genéricos son la respuesta correcta a su problema. Al proporcionar también un parámetro de tipo predeterminado para los genéricos, se pueden usar de forma más ergonómica.
interface Character<T extends string | number = number> { applyDamage (value: T): number; } interface Humanoid<T extends string | number = string | number> extends Character<T> { hp: number; } class Monster implements Humanoid<number> { hp: number = 10; applyDamage(v: number) { this.hp -= v; return v; } } ////////// Use: const monster: Humanoid<number> = new Monster(); // You could also just write it this way: // const monster = new Monster(); monster.applyDamage("hello"); /* ^^^^^^^ Argument of type 'string' is not assignable to parameter of type 'number'.(2345) */ console.log(monster.hp); //=> NaNDesafortunadamente, esta es una de las lagunas en la seguridad de tipos causada por el hecho de que los parámetros del método se verifican de forma bivariante. Esto significa que siempre que haya una relación entre los parámetros de la función, no importa en qué dirección sea esa relación.
Aquí hay un enlace a la sección relacionada del manual de TypeScript: Función Parámetro Bivarianza
El razonamiento para esto se explica en el PR que introduce tipos de función estrictos (es decir, tipos de parámetros contravariantes para firmas de funciones) y es básicamente que si los métodos se verificaran de forma contravariante, la mayoría de los tipos genéricos serían invariantes (por lo que no podría asignar Array<Cat> a Array<Animal>
Una solución es evitar las firmas de métodos y usar firmas de funciones siempre que sea posible:
interface Character { applyDamage: (value : number) => number; } interface Humanoid extends Character { hp:number; applyDamage: (value: number|string) => number } class Monster implements Humanoid { hp:number = 10; applyDamage(v: number) { // error this.hp -= v; return v; } } const monster:Humanoid = new Monster(); // error monster.applyDamage("hello"); console.log(monster.hp); // <-- NaNSi desea obtener más información sobre la varianza, puede ver mi presentación aquí .