4

I'm having problems understanding how to correctly type a constructor function in TS. I'm aware that a common answer would be to use a class, but I'm currently exploring TS features. In my tsconfig.json I have noImplicitAny: true.

My constructor function looks like this in JS:

function User(username) {
     this.username = username
}
User.prototype.age = 57

My first attempt to type the functions relied on the TS docs that explain how to define call signatures:

interface IUser {
    username: string;
    age: number;
}

type UserConstructor = {
    (username: string): void;
    new (username: string): IUser;
}

const User: UserConstructor = function(username: string) {
    this.username = username
}
User.prototype.age = 57

The compiler complains since the value of this is unknown and the call signatures don't seem to match.

After doing some research, I was able to come up with a version that works but I don't really like it:

interface ICUser {
    username: string;
    age: number;
}

function ConstructedUser(this:ICUser, username: string) {
    this.username = username;
}

ConstructedUser.prototype.dateOfBirth = "Freb"

Here's what I don't like about solution nr. 2:

  • I'm not sure I completely understand the explicit passing of this since there aren't any official docs on this.
  • The typing is very verbose and does not separate between properties on the instance and prototype chain.

I wasn't able to find good resources on how to type constructor functions and hoped someone might be able to help.

4
  • Is there a particular reason you don't want to use the class syntax? Typescript can compile it to a constructor function if you set the target language level appropriately. Commented May 7, 2021 at 17:41
  • I'm actually not trying to solve any "real world" problem. I'm just exploring how this would work in TS to learn. Commented May 7, 2021 at 17:41
  • 1
    This answer is kind of late, but the this usage is officially documented since Typescript 2 Commented Aug 4, 2023 at 11:45
  • Also check this part and this other part Commented Aug 4, 2023 at 12:03

1 Answer 1

4

It looks like the answer is that you can't do this without type assertions (e.g. as any), because you aren't supposed to write constructor functions in Typescript. This GitHub issue suggests allowing it, and the suggestion was marked as "declined" and closed:

If anything we'd rather remove the ability to new void functions. The inconsistency is unfortunate but we didn't want to add a large type safety hole for the sake of consistency with a facet we don't even like in the first place.

The proper way to write your code in Typescript is using the class syntax to declare a class. If it's needed for compatibility with older browsers, you can force tsc to convert your class declaration into a constructor function during compilation, by setting the target language level to ES3 or ES5.

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

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.