I have Person
class which implements interface IPerson
. The interface were to have two variants: IPerson1
| IPerson2
interface IPerson {
name: string | "all",
age?: number,
height?: number,
population?: number,
}
interface IPerson1 {
name: string,
age: number,
height: number,
}
interface IPerson2 {
name: "all",
population: number
}
class Person implements IPerson {
name: string;
age?: number|undefined;
height?: number|undefined;
population?: number|undefined;
constructor(name: "all", population: number);
constructor(name: string, age: number, height: number);
constructor(name: string, ageOrPopulation: number, height?: number) {
this.name = name;
if (height) {
this.age = ageOrPopulation;
this.height = height;
} else {
this.population = ageOrPopulation;
}
}
}
new Person("all", 3e6).population // I hope here population is number instead of number | undefined
// I hope Person can implement both interface IPerson1 and IPerson2, and typescript can do type narrowing for me.
It's worth to mention, in my real code, Person
class has so many methods, so I have to use class
for good code structuring.
Is there any workaround for this scenario? Seems like if class
can implments type
, then I can make it implement a union type so TS can do type narrowing for me. playground
CodePudding user response:
You can't directly annotate the type of a constructor. You can however change the type of the class my assigning it to another variable and asserting a different type. With this technique you can then have different constructor signatures returning different types:
interface IPerson { name: string, age?: number, height?: number, population?: number, }
interface IPerson2 { name: "all", population: number }
class Person implements IPerson {
age?: number|undefined;
height?: number|undefined;
population?: number|undefined;
constructor(public name: string, ageOrPopulation: number, height?: number) {
///...
}
}
const PersonCtor = Person as {
new (name: "all", population: number): IPerson2
new (name: string, age: number, height: number): IPerson
}
new PersonCtor("all", 3e6).population // I hope here population is number instead of number | undefined