如何为TypeScript Promise设置拒绝值类型?
Great question! By default, TypeScript's Promise<T> only explicitly types the resolved value—rejected values are treated as unknown (or any in older versions), which leaves you without compile-time checks for what gets passed to reject(). Let's fix that with two key steps: restricting what can be passed to reject when creating the Promise, and ensuring type safety when handling rejections.
Step 1: Create a Typed Promise Factory Function
To enforce that reject() only accepts your desired type (in this case, number), we'll wrap the native Promise constructor in a generic factory function that explicitly types both resolve and reject parameters:
// Factory function to create Promises with typed resolve/reject function createTypedPromise<TResolve, TReject>( executor: ( resolve: (value: TResolve) => void, reject: (reason: TReject) => void ) => void ): Promise<TResolve> { return new Promise(executor); }
Now rewrite your start function using this factory. Notice how we specify <string, number> to set the resolved type as string and rejected type as number:
const someCondition = false; // Example condition const start = (): Promise<string> => { return createTypedPromise<string, number>((resolve, reject) => { if (someCondition) { resolve('correct!'); } else { reject(-1); // ✅ Valid: passes a number // reject('oops'); // ❌ Compile error: Argument of type 'string' is not assignable to type 'number' } }); };
This immediately prevents invalid values from being passed to reject() during development.
Step 2: Enforce Type Safety When Handling Rejections
Even with the factory function, TypeScript still infers rejection values as unknown in .catch() by default. To get compile-time checks here, you have two solid options:
Option A: Use a Type Guard
This is the safest approach because it validates the type at runtime too:
start() .then((result) => console.log('Success:', result)) .catch((err) => { if (typeof err === 'number') { // ✅ err is typed as number here console.log('Error code:', err); } else { // Handle unexpected types (though our factory makes this unlikely) throw new Error(`Unexpected rejection type: ${typeof err}`); } });
Option B: Explicitly Type the Catch Parameter
If you're confident that the rejection will always be a number (thanks to our factory function), you can explicitly type the catch parameter. This will throw a compile error if you try to treat it as the wrong type:
start() .then((result) => console.log('Success:', result)) .catch((err: number) => { // ✅ err is enforced as number; trying to call string methods here will throw a compile error console.log('Error code:', err); // err.toUpperCase(); // ❌ Compile error: Property 'toUpperCase' does not exist on type 'number' });
Why This Works
TypeScript's native Promise type doesn't include rejection typing because the ECMAScript Promise spec allows rejecting with any value. Our factory function adds a layer of compile-time safety by restricting what the executor can pass to reject(), and the catch handling ensures you can't accidentally misuse the rejection type.
内容的提问来源于stack exchange,提问作者Kousha

