【发布时间】:2019-12-07 06:13:23
【问题描述】:
我正在为 TypeScript 中的 API 创建一个包装器。
一个 API 调用可以返回 2 种类型的响应:基本和扩展,具体取决于参数属性。
如果参数属性为真,响应将被扩展。如果未提供参数属性或为 false,则响应将是基本的。
这是代码示例:
interface Args {
token: string;
region: string;
extendedResponse?: boolean;
}
interface BasicResponse {
ID: string;
}
interface ExtendedResponse extends BasicResponse {
extendedResponseProperty: object;
}
function returnResponse(args: Args): BasicResponse | ExtendedResponse {
if (args.extendedResponse) {
return { ID: "foobar", extendedResponseProperty: {} };
}
return {ID: "foobar"}
}
let res1 = returnResponse({ token: "asdf", region: "us", extendedResponse: true });
但是,此代码并未向此方法的使用者显示返回了 ExtendedResponse,而是将类型显示为 BasicResponse | ExtendedResponse,并且未在智能感知中显示 extendedResponseProperty。
我最接近解决这个问题的方法是使用以下代码:
interface Args {
token: string;
region: string;
}
interface ExtendedArgs extends Args {
extendedResponse: true;
}
interface BasicResponse {
ID: string;
}
interface ExtendedResponse extends BasicResponse {
extendedResponseProperty: object;
}
function returnResponse(args: Args): BasicResponse;
function returnResponse(args: ExtendedArgs): ExtendedResponse;
function returnResponse(args: Args | ExtendedArgs): BasicResponse | ExtendedResponse {
if (args as ExtendedArgs) {
return { ID: "foobar", extendedResponseProperty: {} };
}
return {ID: "foobar"}
}
let res1 = returnResponse({ token: "asdf", region: "us" });
let res2 = returnResponse({ token: "asdf", region: "asdf", extendedResponse: true });
但我不太喜欢这种解决方案,因为这种方法的使用者需要处理函数重载和两种类型的输入参数。
只有一个输入参数,它恰好可以有extendedResponse: boolean属性。两个输入参数使其不那么直观。
是否有基于 TypeScript 类型的方法可以解决这个问题?
更新
更好的解决方案是对输入 Args 使用联合类型:
interface Args {
token?: string;
region?: string;
}
interface BasicResponse {
ID: string;
}
interface ExtendedResponse extends BasicResponse {
extendedResponseProperty: object;
}
function returnResponse(args: Args): BasicResponse;
function returnResponse(args: Args & {callbackData: true}): ExtendedResponse;
function returnResponse(args: Args | Args & {callbackData: true}): BasicResponse | ExtendedResponse {
if (args as { callbackData: true }) {
return { ID: "foobar", extendedResponseProperty: {}}
}
return {ID: "foobar"}
}
let res1 = returnResponse({ token: "asdf", region: "us" });
let res2 = returnResponse({ token: "foo", callbackData: true });
它对消费者来说更具可读性,因为它表明添加 callbackData: true 将返回不同的结果,但仍然不理想,因为它仍然是两种不同的参数类型。
【问题讨论】:
标签: typescript