'How to write typescript with constructor function/new keyword?
This is an example from MDN docs for the usage of new
keyword
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const car1 = new Car('Eagle', 'Talon TSi', 1993);
I believe, the TS version of the function would be:
/* car type */
type CarDetails = {
make: string;
model: string;
year: number;
}
/* setting this to type CarDetails */
function Car(this:CarDetails, make: string, model:string, year:number) {
this.make = make;
this.model = model;
this.year = year;
}
This gives me intellisense/autocomplete while writing the method but how do I make TS infer types while creating an instance with new
keyword. Even after typescripting the method, creating an instance like this:
const car1 = new Car('Eagle', 'Talon TSi', 1993);
still keeps car1
as type any
How to make car1
's type infer to be Car
method's this
type ?
(without explicitly setting type for the instance object, const car1: CarDetails = new Car(...;
)
Solution 1:[1]
You could use classes instead:
class Car {
make: string;
model: string;
year: number;
constructor(make: string, model: string, year: number) {
this.make = make;
this.model = model;
this.year = year;
}
}
// usage is the same
const car1 = new Car('Eagle', 'Talon TSi', 1993);
Solution 2:[2]
Obviously the class syntax should be the way to go, but as you I'm also running in circles trying to find the right solution that outputs the old valid JS syntax. This is a good approximation that I've found in this random answer and it's poorly explained in the official Typescript documentation. Here is the relevant part that I've modified to make it better:
// Only instance members here.
export interface Circle { // Name the interface with the same than the var.
radius: number;
area: () => number;
perimeter: () => number;
}
// You could define static members here.
interface CircleConstructor {
new(radius: number): Circle;
}
export const Circle = function(this: Circle, radius: number) {
const pi = 3.14;
this.radius = radius;
this.area = function () {
return pi * radius * radius
}
this.perimeter = function () {
return 2 * pi * radius;
}
} as unknown /*as any*/ as CircleConstructor; // Note the trust-me casting
const c = new Circle(3); // okay
This comes with some issues. For instance, the fact that it's using any
type which is forbidden or the necessary use of the as
operator which is mega-ugly. As improvement, I've used unknown
instead of any
but the core problem remains. This makes the lint tool to not complain, so it's a big improvement over the any
.
This is the best solution I've found so far. Typescript devs are aware of this, but they have decided to not provide support for this kind of "syntax".
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | User81646 |
Solution 2 |