为返回函数包装器的原生JS工厂函数编写d.ts遇类型传递问题
To properly type your chainable factory function and preserve intermediate types through each stage, you'll need to use generics to carry type information from one function to the next. Here's a step-by-step solution tailored to your simplified function structure:
Step 1: Understand the Function Chain
Your factory has three distinct stages:
- Accepts
xandy(with default0), computesz = x + y - Accepts a function
fnthat operates onz - Accepts arbitrary arguments and returns a value based on
fn(z)and those arguments
Step 2: Write the Type Definitions
Create a your-module.d.ts file with the following code. We'll use a helper type to compute the type of z, and generics to pass types through each stage:
// Helper type to compute the type of z = x + y type Add<T, U> = T extends string ? string : U extends string ? string : number; export function factory<T, U = number>(x: T, y?: U): // Stage 2: takes fn that accepts z and returns R <R>(fn: (z: Add<T, U>) => R) => // Stage 3: takes args and returns a combined result (adjust based on your actual logic) <Args extends any[]>(...args: Args) => Promise<[R, Args]>;
Breakdown of the Types:
Add<T, U>: Handles the type ofz—adding a string to anything results in a string; otherwise, it's a number. Adjust this if your function supports other addition types (like bigints).factory<T, U = number>: Generic overT(type ofx) andU(type ofy, defaulting tonumbersinceyhas a default value of0).- Stage 2: The returned function is generic over
R(the return type offn), ensuringfnreceives the correct type ofz. - Stage 3: The final function is generic over
Args(the arguments passed to it), preserving their type in the return value.
Step 3: Test the Type Definitions
Here's how the types work in practice:
import { factory } from './your-module'; // Case 1: x and y are numbers const stage1 = factory(5, 3); // z is typed as number (8) const stage2 = stage1((z) => z * 2); // z is number, returns number (16) const result = stage2('a', true); // result is Promise<[number, [string, boolean]]> // Case 2: x is string, y is number const stage1Str = factory('hello', 5); // z is typed as string ("hello5") const stage2Str = stage1Str((z) => z.length); // z is string, returns number (6) const resultStr = stage2Str(100, null); // result is Promise<[number, [number, null]]>
Adjust for Your Exact Logic
If your final function returns something different (e.g., not a Promise, or a different structure), modify the return type of the innermost function. For example, if the final function returns just the result of fn(z):
// Modified final stage return type <Args extends any[]>(...args: Args) => R;
Or if fn returns a Promise:
// Stage 2: fn returns Promise<R> <R>(fn: (z: Add<T, U>) => Promise<R>) => // Stage 3: returns Promise<R> <Args extends any[]>(...args: Args) => Promise<R>;
内容的提问来源于stack exchange,提问作者Paul S.

