TypeScript:从函数类型获取实例类型及声明getInstance方法类型
Got it, let's break down these two TypeScript challenges step by step—they’re focused on constructor functions and their instance types, which come up a lot in class-based or factory-style code.
TypeScript has a built-in utility type specifically for this: InstanceType<T>. It extracts the instance type of a constructor function type T (i.e., the type you get when you new up the function).
Example 1: Class Constructor
If you have a class, use typeof ClassName to get its constructor type, then pass that to InstanceType:
class Car { model: string; year: number; constructor(model: string, year: number) { this.model = model; this.year = year; } } // Extract the instance type of Car type CarInstance = InstanceType<typeof Car>; // CarInstance is equivalent to { model: string; year: number; constructor: typeof Car }
Example 2: Custom Constructor Type
If you’re working with a generic constructor type (common in factory functions), InstanceType still works seamlessly:
// Define a generic constructor type type Constructor<T = {}> = new (...args: any[]) => T; // Extract instance type from a constructor that returns { id: string } type IdInstance = InstanceType<Constructor<{ id: string }>>; // IdInstance is { id: string }
getInstance Method on Function.prototype with Type Declarations To add a getInstance method to all functions (and ensure TypeScript recognizes it with correct types), we need two things: a global interface extension for type declarations, and the actual method implementation.
Step 1: Declare the Type
First, extend the global Function interface to add getInstance. We’ll make it generic so it infers the instance type automatically:
// Define a reusable constructor type (matches any function that can be `new`ed) type Constructor<T = {}> = new (...args: any[]) => T; // Extend the global Function interface declare global { interface Function { /** * Creates and returns a new instance of the constructor function * @param args Arguments to pass to the constructor * @returns A new instance of the constructor's type */ getInstance<T extends Constructor>(this: T, ...args: ConstructorParameters<T>): InstanceType<T>; } }
ConstructorParameters<T>extracts the argument types of the constructor, so TypeScript will enforce passing the correct args.this: Tensures the method can only be called on a valid constructor function (TypeScript will throw an error if you try to call it on a non-constructor function like an arrow function).
Step 2: Implement the Method
Now add the actual implementation to Function.prototype. We’ll add a check to ensure we’re dealing with a valid constructor:
Function.prototype.getInstance = function(...args: any[]) { // Guard clause: Ensure this is a constructor function (has a prototype and is callable) if (typeof this !== 'function' || !this.prototype) { throw new Error('getInstance can only be called on constructor functions (classes or function constructors)'); } // Create and return a new instance using the constructor and provided args return new this(...args); };
Example Usage
Now you can use getInstance on any constructor, with full TypeScript type support:
class User { username: string; constructor(username: string) { this.username = username; } } // TypeScript infers `user` as type User const user = User.getInstance('john_doe'); console.log(user.username); // "john_doe" // If you pass the wrong args, TypeScript throws an error: // User.getInstance(); // Error: Expected 1 arguments, got 0
Notes
- Arrow functions can’t be used as constructors (they don’t have a
prototypeproperty), so callinggetInstanceon an arrow function will throw a runtime error (and TypeScript will flag it at compile time too). - This works with traditional function constructors too, not just classes:
function Book(title: string) { this.title = title; } const book = Book.getInstance('The TypeScript Handbook'); // book is typed as InstanceType<typeof Book> (has a `title` property)
内容的提问来源于stack exchange,提问作者pmingkr

