1

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(...; )

19
  • Why do you want to use a constructor function over class here? Commented Mar 2, 2022 at 7:10
  • Less lines of code, probably. Commented Mar 2, 2022 at 7:12
  • You must be getting a 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type. error.. Don't you ?? Commented Mar 2, 2022 at 7:16
  • Great, you've saved up on so much work that you need help with adding more to your code in order to get it to behave as you want... Doesn't it seem like your approach while maybe shorter actually takes more time and effort to do? Also the maybe is a big one: tsplay.dev/WkMX2N your approach is of comparable length to a normal class. But the class can be shorter. Commented Mar 2, 2022 at 7:18
  • @NalinRanjan - No I don't Commented Mar 2, 2022 at 7:19

3 Answers 3

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".

Sign up to request clarification or add additional context in comments.

Comments

0

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

1 Comment

I understand it can be done using a class. But my question is specifically for constructor functions.
0

Recently had to make support for both ways and ended up with something like this

export declare class Maybe<Value> {
  constructor(status: "resolved" | "rejected", state: Value | unknown);
}
export function Maybe<Value>(this: Maybe<unknown> | undefined, status: "resolved" | "rejected", state: Value | unknown): Maybe<Value> {
  const instance = this ?? Object.create(Maybe.prototype);
  return instance;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.