A constructor in TypeScript is the class's constructor method with typed parameters. It has no return type annotation: it always produces an instance of the class.
Writing constructor(): Product is error TS1093 (Type annotation cannot appear on a constructor declaration). Everything else about how new works is plain JavaScript.
Parameter Properties
The pattern above (declare a field, take a parameter, copy it over) is so common that TypeScript has a shorthand. Put public, private, protected or readonly before a constructor parameter and it becomes a field:
This is one of the few TypeScript features that generates code. The compiler writes the assignments for you:
class Product {
name;
price;
sku;
constructor(name, price, sku) {
this.name = name;
this.price = price;
this.sku = sku;
}
// ...
}
Because it is not just erased types, parameter properties do not run under Node's built-in type stripping (node file.ts fails with ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX), and the erasableSyntaxOnly compiler option reports them as error TS1294. Projects that run .ts files directly write the fields out by hand.
Optional and Default Parameters
Constructor parameters follow the same rules as function parameters: ? makes one optional, a default value makes it optional and fills it in, and required parameters come first.
Parameter properties can have defaults too. The type of color inside the class is string | undefined, so code that uses it must check for undefined first.
For constructors with many options, one options object reads better than a long positional list: constructor(opts: { prefix: string; level?: "info" | "debug" }).
Field Initialization Order
Field initializers run before the constructor body, and parameter properties are assigned at the start of the constructor body. So a field initializer cannot read a parameter property. TypeScript catches it:
index.ts(3,18): error TS2729: Property 'size' is used before its initialization.
index.ts(3,30): error TS2729: Property 'size' is used before its initialization.
At runtime the initializer would see undefined and produce NaN. Compute the value in the constructor body instead:
class Grid {
cells: number;
constructor(public size: number) {
this.cells = size * size;
}
}
console.log(new Grid(3).cells); // 9
Constructor Overloads
A class has exactly one constructor implementation, but you can list several overload signatures above it. Callers see only the overloads; the implementation signature must be compatible with all of them.
Overloads get hard to read past two or three shapes. Static factory methods with descriptive names (Color.fromHex("#ff8800"), Color.fromRgb(10, 20, 30)) are often clearer and need no type narrowing inside one body.
Calling super in a Subclass
A derived class that declares its own constructor must call super(...) with the parent's arguments, and must do it before touching this. Forgetting the call is error TS2377 (Constructors for derived classes must contain a 'super' call), and using this first is TS17009 ('super' must be called before accessing 'this' in the constructor of a derived class). Both mirror JavaScript runtime rules.
class Animal {
constructor(public name: string) {}
}
class Dog extends Animal {
tricks: string[];
constructor(name: string, ...tricks: string[]) {
super(name); // must come first
this.tricks = tricks;
}
}
const rex = new Dog("Rex", "sit", "roll");
console.log(rex); // Dog { name: 'Rex', tricks: [ 'sit', 'roll' ] }
A subclass that adds no constructor inherits the parent's, with the same parameter types. More on subclasses in inheritance.
Private Constructors and Async Setup
A private constructor can only be called from inside the class. Outside, new is error TS2673. This is how you force callers through a factory, for a singleton or for setup that has to be asynchronous (constructors cannot be async).
private here is a compile-time rule only. The emitted JavaScript has an ordinary constructor, so plain JavaScript code could still call new Connection(...).
Constructor Types
To accept a class as a value, type the parameter with a construct signature: new (...args) => Instance. typeof MyClass also works, but it ties the parameter to that one class's constructor signature and static members.
ConstructorParameters and InstanceType extract the parameter tuple and the instance type from a constructor type; they are covered with the other function helpers in ReturnType and Parameters.
Frequently Asked Questions
What are parameter properties in TypeScript?
A constructor parameter with a modifier (public, private, protected or readonly) declares a field and assigns it in one step. constructor(private name: string) {} is short for declaring private name: string and writing this.name = name. The compiler generates that assignment in the output.
Can a TypeScript class have multiple constructors?
Not multiple implementations. A class has one constructor, but you can write several overload signatures above it so callers see distinct parameter lists. Static factory methods such as Color.fromHex() and Color.fromRgb() are often clearer than overloads.
Can a constructor be async in TypeScript?
No. A constructor always returns the new instance, never a promise, and async constructor() is rejected with error TS1089 ('async' modifier cannot appear on a constructor declaration). Use a private constructor plus a static async create() method that does the asynchronous work and then calls new.
How do I type a class constructor as a parameter?
Use a construct signature: new (name: string) => User, or typeof User for that exact class. A generic factory looks like function make<T>(ctor: new () => T): T { return new ctor(); }. ConstructorParameters<typeof User> gives the parameter list as a tuple.
Why do I get "'super' must be called before accessing 'this'"?
That is error TS17009. In a class that extends another, the parent constructor creates the object, so this does not exist until super(...) has run. Move the super call above any line that touches this.