TypeScript:如何推断参数化类泛型绑定的返回类型及相关问题
Hey there, let's break down your TypeScript issues step by step! First, let's start with a clear example of the code structure you're working with (based on your description):
// 父类定义 abstract class Command<R> { abstract execute(): Promise<R>; } // 登录返回对象 interface LoginResult { success: boolean; token: string; } // 登录命令子类 class LoginCommand extends Command<LoginResult> { constructor(private username: string, private password: string) { super(); } async execute(): Promise<LoginResult> { // 模拟API返回 return { success: true, token: "auth-token-123" }; } } // 原来的ask方法(导致错误的版本) async function ask(command: Command) { return command.execute(); } // 调用时出现错误 async function runLogin() { const result = await ask(new LoginCommand("george", "pass123")); console.log(result.success); // [ts] Property 'success' does not exist on type '{}' }
问题1:如何修改方法签名,让Command中的R正确推断为返回类型?
The fix here is to preserve the generic type information in your ask method. Right now, when you use Command without a generic parameter, TypeScript defaults it to Command<{}>, which erases the specific return type of your subclass.
Update the ask method to explicitly carry the generic type R from the Command:
async function ask<R>(command: Command<R>): Promise<R> { return command.execute(); }
With this change, when you call ask(new LoginCommand(...)), TypeScript will automatically infer that R is LoginResult. Now accessing result.success will work without errors, since the return type is correctly typed as LoginResult.
问题2:为何ask方法会接受参数却丢失类型信息?
When you define ask with command: Command (no generic argument), TypeScript treats this as Command<{}> (the default type for unbound generics in older TS versions, or unknown in newer strict mode, but your error points to {}).
Since LoginCommand extends Command<LoginResult>, and LoginResult is a subtype of {}, TypeScript allows passing it into the ask method (this is a form of type compatibility for generics). However, this compatibility comes at the cost of losing the specific R type information—TypeScript can't know that the command returns LoginResult, so it falls back to the default {}, hence the error when accessing success.
By adding the generic parameter to ask, you're telling TypeScript to "carry through" the specific return type of the Command instance you pass in, avoiding this type erasure.
内容的提问来源于stack exchange,提问作者GeorgeStone

