TypeScript:基于参数的类类型的函数重载

时间:2019-01-30 20:08:25

标签: typescript overloading

是否可以根据参数的类类型来应用TypeScript函数的重载?

我意识到“类”将在输出中被编译为普通函数,但我希望根据输入类型来进行类型检查。

目标是为服务器通信创建一个send()函数,该函数根据请求的类型返回类型化的响应。但是,无论传入的类类型如何,TypeScript似乎总是选择第一个重载。

interface IRequest {
  getBody(): object;
}

class UserRequest implements IRequest {
  getBody() {
    return { type: 'user', id: 7 };
  }
}

class CompanyRequest implements IRequest {
  getBody() {
    return { type: 'company', id: 42 };
  }
}

interface IUserResponse {
  userName: string;
}

interface ICompanyResponse {
  companyName: string;
}

function send(request: UserRequest): Promise<IUserResponse>;
function send(request: CompanyRequest): Promise<ICompanyResponse>;
async function send(request: IRequest): Promise<any> {
  const response = await fetch('https://example.com/service', {
    body: request.getBody(),
  });
  return response.json();
}

async function test() {

  // Works
  const userResponse = await send(new UserRequest());
  userResponse.userName;

  // Error: [ts] Property 'companyName' does not exist on type 'IUserResponse'. [2339]
  const companyResponse = await send(new CompanyRequest());
  companyResponse.companyName;

}

交换声明的重载的顺序可解决此问题(返回类型始终为CompanyRequest而不是UserRequest)。

2 个答案:

答案 0 :(得分:2)

您的问题似乎是编译器认为UserRequestCompanyRequest在结构上是兼容的,这意味着它们本质上是相同的类型。因此,总是选择第一个过载,并且会发生坏事。避免这种情况的最简单方法是向至少一种类型添加属性,以便编译器recognizes they are distinct types。这是一种可能的方法:

class UserRequest implements IRequest {
  getBody() {
    return { type: 'user', id: 7 };
  }
  readonly className = "UserRequest"
}

class CompanyRequest implements IRequest {
  getBody() {
    return { type: 'company', id: 42 };
  }
  readonly className = "CompanyRequest"
}

在这种情况下,readonly属性className会获得一些不同的文字字符串值。希望能有所帮助。祝你好运!

答案 1 :(得分:1)

一般方法呢?

async function send<T>(request: T): Promise<T> {
    const response = await fetch('https://example.com/service', {
        body: request.getBody(),
    });
    return response.json();
}