Constructor function type
Basic Concepts of Constructor Function Types in TypeScript
Constructor function types in TypeScript are used to describe class constructors. They define the parameter types and return type required when creating a class instance. Constructor function types are typically used with the new
keyword to indicate that this is a constructor function rather than a regular function.
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick(): void;
}
function createClock(
ctor: ClockConstructor,
hour: number,
minute: number
): ClockInterface {
return new ctor(hour, minute);
}
Syntax of Constructor Function Types
The syntax for constructor function types is similar to that of regular function types, but the new
keyword must be added before the parameter list. The basic form is as follows:
type Constructor = new (...args: any[]) => any;
More specific constructor types can be defined like this:
type PointConstructor = new (x: number, y: number) => Point;
Use Cases for Constructor Function Types
Factory Functions
Constructor function types are often used to create factory functions, which take constructors as parameters and return new instances:
class Car {
constructor(public model: string) {}
}
type CarConstructor = new (model: string) => Car;
function createCar(ctor: CarConstructor, model: string): Car {
return new ctor(model);
}
const myCar = createCar(Car, "Tesla");
Class Decorators
Constructor function types are essential when implementing class decorators:
function logged<T extends new (...args: any[]) => any>(ctor: T) {
return class extends ctor {
constructor(...args: any[]) {
console.log(`Creating instance with args: ${args}`);
super(...args);
}
};
}
@logged
class Person {
constructor(public name: string) {}
}
Construct Signatures and Instance Types
Constructor function types can be broken down into construct signatures and instance types:
interface AnimalConstructor {
// Construct signature
new (name: string): Animal;
// Static method
createDefault(): Animal;
}
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal {
constructor(public name: string) {}
makeSound() {
console.log("Woof!");
}
static createDefault() {
return new Dog("Default");
}
}
Generic Constructor Function Types
Constructor function types can also use generics for increased flexibility:
type GenericConstructor<T> = new (...args: any[]) => T;
function createInstance<T>(ctor: GenericConstructor<T>, ...args: any[]): T {
return new ctor(...args);
}
class Book {
constructor(public title: string) {}
}
const myBook = createInstance(Book, "TypeScript Deep Dive");
Constructor Function Types and Inheritance
When dealing with class inheritance, constructor function types can ensure that subclasses meet specific construction requirements:
class Animal {
constructor(public name: string) {}
}
type AnimalConstructor = new (name: string) => Animal;
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name);
}
}
function createAnimal(ctor: AnimalConstructor, name: string): Animal {
return new ctor(name);
}
// Can pass Dog because it satisfies the AnimalConstructor type
const myDog = createAnimal(Dog, "Buddy");
Constructor Function Types and Mixins
Constructor function types are particularly useful when implementing mixins:
type Constructor<T = {}> = new (...args: any[]) => T;
function Timestamped<TBase extends Constructor>(Base: TBase) {
return class extends Base {
timestamp = Date.now();
};
}
class User {
constructor(public name: string) {}
}
const TimestampedUser = Timestamped(User);
const user = new TimestampedUser("Alice");
console.log(user.timestamp);
Advanced Patterns with Constructor Function Types
Parameter Destructuring
Constructor function types can be used with parameter destructuring:
type Point3DConstructor = new (options: { x: number; y: number; z: number }) => Point3D;
class Point3D {
constructor(public x: number, public y: number, public z: number) {}
}
function createPoint3D(ctor: Point3DConstructor, options: { x: number; y: number; z: number }) {
return new ctor(options);
}
Optional Parameters
Constructor function types can also include optional parameters:
type PersonConstructor = new (name: string, age?: number) => Person;
class Person {
constructor(public name: string, public age?: number) {}
}
Constructor Function Types and Interface Merging
Interfaces can include construct signatures, allowing them to describe constructors:
interface StringArray {
[index: number]: string;
}
interface StringArrayConstructor {
new (size: number): StringArray;
from(array: any[]): StringArray;
}
declare const StringArray: StringArrayConstructor;
const myArray = new StringArray(10);
const otherArray = StringArray.from([1, 2, 3]);
Constructor Function Types and Type Inference
TypeScript can infer instance types from constructor function types:
function getInstance<T>(ctor: new () => T): T {
return new ctor();
}
class Widget {
id = Math.random();
}
const widget = getInstance(Widget); // widget is inferred as type Widget
Constructor Function Types and Abstract Classes
Abstract class constructor function types require special handling:
abstract class Animal {
abstract makeSound(): void;
}
type AnimalConstructor = new () => Animal;
// Error: Cannot directly instantiate an abstract class
// const animal = new Animal();
// But can be used as a type constraint
function createAnimalSubclass(ctor: AnimalConstructor): Animal {
class Temp extends ctor {}
return new Temp();
}
Constructor Function Types and Private Constructors
For singleton patterns, private constructors can be represented with types:
class Singleton {
private static instance: Singleton;
private constructor() {}
static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
// Constructor type can be represented like this
type SingletonConstructor = typeof Singleton;
Constructor Function Types and Overloading
Constructor function types can also represent overloaded constructors:
interface PointConstructor {
new (x: number, y: number): Point;
new (coord: [number, number]): Point;
}
class Point {
constructor(...args: [number, number] | [number, number]) {
// Implementation of overload logic
}
}
Constructor Function Types and Conditional Types
Combining with conditional types allows for more flexible constructor types:
type ConstructorArg<T> = T extends new (arg: infer A) => any ? A : never;
class Foo {
constructor(public value: string) {}
}
type FooArg = ConstructorArg<typeof Foo>; // string
Constructor Function Types and Mapped Types
Mapped types can be used to transform constructor function types:
type WithName<T> = T & { name: string };
type NamedConstructor<T> = new (...args: any[]) => WithName<T>;
class Person {
constructor(public name: string, public age: number) {}
}
type NamedPersonConstructor = NamedConstructor<Person>;
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn