Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

191
Views
Why does TypeScript allow implementation of method expecting number or string to only accept number?

I defined an applyDamage method to accept number or string, but implemented it with only with a number argument. When I call this method using base class, I have incorrect behavior. Why doesn't TypeScript show an 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); // <-- NaN
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

You defined the signature of the method in Humanoid for applyDamage to take an input value of string | number;

TS just checks that your implementation for Monster class has the appropriate signature and returns the defined type. It's up to you to write a method body that is safe.

It seems that maybe you want to use a overload. https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads

over 4 years ago · Santiago Trujillo Report

0

As others have pointed out: an overload would work... but the way that I read your code, it seems like you only want to implement a subtype of the union parameter, so I think generics are the right answer to your issue. By also providing a default type parameter for the generics, they can be used more ergonomically.

TS Playground

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); //=> NaN

over 4 years ago · Santiago Trujillo Report

0

Unfortunately this is one of the loopholes in type safety caused by the fact that method parameters are checked bi-variantly. This means that as long as there is a relationship between the function parameters it doesn't matter in which direction that relationship is.

Here's a link to the related TypeScript handbook section: Function Parameter Bivariance

The reasoning for this is explained in the PR that introduces strict function types (ie contravariant parameter types for function signatures) and is basically that if methods were checked contravariantly it would result in most generic types being invarinat (so you couldn't assign Array<Cat> to Array<Animal>

One solution is to avoid method signatures and use function signatures wherever possible:

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); // <-- NaN

Playground Link

If you want to learn more about variance, you can watch my presentation on it here

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!