TypeScript Constructor Declared In An Interface
ID |
javascript.ts_constructor_in_interface |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
best-practice, reliability, typescript |
Description
Reports a member named constructor declared in a TypeScript interface, where the construct signature is spelled new (…).
Only a method signature is reported. new (…) is the correct form and is left alone, as are a class constructor and an object literal’s constructor() method, which are not interface members at all.
Rationale
// Bad
interface Repository {
constructor(url: string): void;
}
-
An interface describes the shape of an instance, and an instance has no constructor to call. What this declares is a method whose name happens to be
constructor. -
TypeScript accepts it without a word, so the interface compiles and reads as though it constrained construction while it constrains nothing of the sort: a class satisfies it by declaring an actual method of that name, and a class with a real constructor of that signature does not satisfy it at all.
-
The name also collides with something that exists — every object inherits
constructorfrom its prototype — so the declaration narrows a member that is already there and typed differently.
Remediation
To describe a value that can be constructed, use a construct signature. To constrain the instances, leave the constructor to the implementing class.
// Good — the interface describes the factory
interface RepositoryFactory {
new (url: string): Repository;
}
function build(factory: RepositoryFactory, url: string): Repository {
return new factory(url);
}
// Good — the interface describes the instance; the class owns its constructor
interface Repository {
find(id: string): unknown;
}
class HttpRepository implements Repository {
constructor(private url: string) {}
find(id: string): unknown {
return null;
}
}