【问题标题】:Typescript: reference to interface in variable打字稿:引用变量中的接口
【发布时间】:2018-07-24 12:43:02
【问题描述】:

在实现服务器通信的客户端时,我碰巧遇到了以下问题:如何将对接口的引用存储在变量中。

我有一个接口,其中包含有关特定 RESTfull 后端调用的所有信息:

export interface IEndpoint {
  path: string,
  method: HTTP_METHOD,
  data: any,
  response: any
}

创建这个元素的实例(ISomeInterface 和 IAnotherInterface 是我后面要参考的接口):

export const GET_TEST: IEndpoint = {
  path: 'api/test',
  method: HTTP_METHOD.GET,
  data: <ISomeInterface>{},
  response: <IAnotherInterface>{}
};

目标是使用数据和响应字段作为 Promise 中的类型引用(元是 IEndpoint 的一个实例):

new Promise<meta.response>((resolve) => {
  ...
});

Promise 的回调类型 (meta.response) 是我无法提取我之前分配的类型/接口的地方。

【问题讨论】:

  • meta.response 不是一个类型,它是一个。你在什么背景下定义承诺?给minimal reproducible example。这可以通过泛型和/或推理来完成,而不是像那样指定承诺类型。
  • 为什么不Promise&lt;IAnotherInterface&gt;

标签: angular typescript ionic-framework interface


【解决方案1】:

值和类型存在于两个不同的域中。类型在编译时被擦除,因此我们无法像您尝试那样将类型分配给接口字段。

我们可以做的是在类型域中工作,并使用泛型参数将dataresponse 类型保留在IEndpoint 类型中,并在需要时提取它们。

export interface IEndpoint<TData, TResponse> {
    path: string,
    method: HTTP_METHOD,
    // just here because typescript doesn't handle unused generics well
    _data?: TData,
    _response?: TResponse
}

function makeRequest<T extends IEndpoint<any, any>>(endPoint: T, data: T['_data']): Promise<T['_response']> {
    return null as any// actual call
}

interface ISomeInterface { data: string }
interface IAnotherInterface { result: string }
export const GET_TEST: IEndpoint<ISomeInterface, IAnotherInterface> = {
    path: 'api/test',
    method: "GET"
};
// Takes in ISomeInterface returns Promise<IAnotherInterface> 
makeRequest(GET_TEST, { data: ""}).then(r=> r.result);

正如@jeroen-vervaeke 指出的那样,makeRequest 也可以用更简单的方式输入,效果相同:

function makeRequest2<TData, TResponse>(endPoint: IEndpoint<TData, TResponse>, data: TData): Promise<TResponse>{
    return null as any;
}

【讨论】:

  • 你不认为这对你的 makeRequest 方法来说是一个更清晰的签名吗? function makeRequest&lt;T extends IEndpoint&lt;TData, TResponse&gt;, TData, TResponse&gt;(endPoint: T, data: TData): Promise&lt;TResponse&gt; {},这样就不用依赖字段名了
  • @JeroenVervaeke 不幸的是,这将无法正常工作,TRsponse 将无法正确推断。使用您的版本,这就是调用 makeRequest(GET_TEST, { data: ""}) 推断出来的内容:makeRequest&lt;IEndpoint&lt;ISomeInterface, IAnotherInterface&gt;, { data: string; }, {}&gt;
  • 你是对的。这是正确的签名:function makeRequest&lt;TData, TResponse&gt;(endPoint: IEndpoint&lt;TData, TResponse&gt;, data: TData): Promise&lt;TResponse&gt;
  • @JeroenVervaeke 是的,你是对的,它也可以工作 :)
【解决方案2】:

您可以使用泛型类解决您的问题并将方法绑定到此类:

export class Endpoint<T, U> {
  constructor(
    private path: string,
    private method: HTTP_METHOD,
    private data: T,
    private response: U
  ) {}

  // your new promise method there
}

【讨论】:

    【解决方案3】:

    您参考meta部分:

    new Promise<meta.response>((resolve) => {
      ...
    });
    

    因为它代表一个类型,而它代表一个值。您可以使用typeof 解决它:

    new Promise<typeof (meta.response)>((resolve) => {
      ...
    });
    

    或者通过直接引用响应类型:

    new Promise<IAnotherInterface>(resolve => {
      ...
    });
    

    除此之外,TS 团队强烈建议使用as 作为转换运算符,而不是&lt;&gt;

    export const GET_TEST: IEndpoint = {
      path: 'api/test',
      method: HTTP_METHOD.GET,
      data: {} as,ISomeInterface
      response: {} as IAnotherInterface
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-23
      • 2017-09-02
      • 1970-01-01
      • 2017-04-15
      • 2018-02-27
      • 2022-01-25
      • 2015-05-16
      • 1970-01-01
      相关资源
      最近更新 更多