Typescript 依赖于函数参数属性的函数返回类型
我正在为TypeScript中的API创建一个包装器 一个API调用可以返回两种类型的响应:基本响应和扩展响应,具体取决于参数属性 如果参数属性为true,则响应将被扩展。如果参数属性未提供或为false,则响应将是基本的 以下是代码示例:Typescript 依赖于函数参数属性的函数返回类型,typescript,Typescript,我正在为TypeScript中的API创建一个包装器 一个API调用可以返回两种类型的响应:基本响应和扩展响应,具体取决于参数属性 如果参数属性为true,则响应将被扩展。如果参数属性未提供或为false,则响应将是基本的 以下是代码示例: 接口参数{ 令牌:字符串; 区域:字符串; extendedResponse?:布尔值; } 界面碱基应答{ ID:字符串; } 接口扩展响应扩展基本响应{ 扩展响应属性:对象; } 函数返回响应(args:args):基本响应|扩展响应{ if(参数ext
接口参数{
令牌:字符串;
区域:字符串;
extendedResponse?:布尔值;
}
界面碱基应答{
ID:字符串;
}
接口扩展响应扩展基本响应{
扩展响应属性:对象;
}
函数返回响应(args:args):基本响应|扩展响应{
if(参数extendedResponse){
返回{ID:“foobar”,扩展响应属性:{};
}
返回{ID:“foobar”}
}
让res1=returnResponse({令牌:“asdf”,区域:“us”,extendedResponse:true});
游乐场:
但是,此代码不向此方法的使用者显示已返回扩展响应
,它将类型显示为基本响应|扩展响应
,并且不显示intellisense中的扩展响应属性
我最接近解决这个问题的方法是使用以下代码:
接口参数{
令牌:字符串;
区域:字符串;
}
接口扩展参数扩展参数{
扩展响应:正确;
}
界面碱基应答{
ID:字符串;
}
接口扩展响应扩展基本响应{
扩展响应属性:对象;
}
函数返回响应(args:args):基本响应;
函数returnResponse(args:ExtendedArgs):ExtendedResponse;
函数返回响应(args:args | ExtendedArgs):基本响应| ExtendedResponse{
if(args作为扩展args){
返回{ID:“foobar”,扩展响应属性:{};
}
返回{ID:“foobar”}
}
让res1=returnResponse({令牌:“asdf”,区域:“us”});
让res2=returnResponse({令牌:“asdf”,区域:“asdf”,extendedResponse:true});
连结至游乐场:
但是我并不喜欢这个解决方案,因为这个方法的使用者需要处理函数重载和两种类型的输入参数。
只有一个输入参数,恰好它可以有extendedResponse:boolean
属性。两个输入参数使其不那么直观
是否有一种基于类型脚本的方法可以解决这个问题?
更新 更好的解决方案是为输入参数使用联合类型:
接口参数{
令牌?:字符串;
区域?:字符串;
}
界面碱基应答{
ID:字符串;
}
接口扩展响应扩展基本响应{
扩展响应属性:对象;
}
函数返回响应(args:args):基本响应;
函数returnResponse(args:args&{callbackData:true}):ExtendedResponse;
函数returnResponse(args:args | args&{callbackData:true}):基本应答|扩展响应{
if(args为{callbackData:true}){
返回{ID:“foobar”,扩展响应属性:{}
}
返回{ID:“foobar”}
}
让res1=returnResponse({令牌:“asdf”,区域:“us”});
让res2=returnResponse({令牌:“foo”,callbackData:true});
消费者更容易阅读,因为它表明添加
callbackData:true
将返回不同的结果,但仍然不理想,因为它仍然是两种不同的参数类型。如果您不喜欢重载,可以使用这样的泛型:
interface Args {
token: string;
region: string;
extendedResponse?: true;
}
interface BasicResponse {
ID: string;
}
interface ExtendedResponse extends BasicResponse {
extendedResponseProperty: object;
}
function returnResponse<A extends Args>(args: A): A extends { extendedResponse: true} ? ExtendedResponse : BasicResponse {
if (args.extendedResponse === true) {
return { ID: "foobar", extendedResponseProperty: {} } as any;
}
return {ID: "foobar"} as any
}
let res1 = returnResponse({ token: "asdf", region: "us" });
let res2 = returnResponse({ token: "asdf", region: "asdf", extendedResponse: true });
接口参数{
令牌:字符串;
区域:字符串;
扩展响应?:true;
}
界面碱基应答{
ID:字符串;
}
接口扩展响应扩展基本响应{
扩展响应属性:对象;
}
函数returnResponse(args:A):扩展{extendedResponse:true}?扩展应答:基本应答{
if(args.extendedResponse===true){
返回{ID:“foobar”,extendedResponseProperty:{}如有;
}
返回{ID:“foobar”}
}
让res1=returnResponse({令牌:“asdf”,区域:“us”});
让res2=returnResponse({令牌:“asdf”,区域:“asdf”,extendedResponse:true});
但老实说,我喜欢你的代码沙盒中的代码。它描述了在没有额外魔法的情况下发生的事情,并且易于阅读
另外,我不确定你所说的“消费者将不得不处理方法过载”是什么意思——消费者得到了他们所调用的,而不是或多或少。您在这里描述的是一种特定的行为,无论您如何描述,不同的输入参数将导致不同的输出,并且一旦您的运行时代码这样做,使用者将不得不以任何方式处理这种行为