Typescript:变量中引用接口

3

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

我有一个接口,它保存了关于特定RESTful后端调用的所有信息:

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 中使用数据和响应字段作为类型引用(meta 是 IEndpoint 的一个实例):
new Promise<meta.response>((resolve) => {
  ...
});

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


meta.response不是一种类型,而是一个。你在什么上下文中定义了这个promise?提供一个最小可复现示例。可能可以使用泛型和/或推断来完成这个操作,而不是像那样指定promise类型。 - jonrsharpe
为什么不使用 Promise<IAnotherInterface> - Niragh
3个回答

3

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

我们可以做的是在类型域中使用泛型参数将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<T extends IEndpoint<TData, TResponse>, TData, TResponse>(endPoint: T, data: TData): Promise<TResponse> {},这样你就不需要依赖字段名称了。 - Jeroen Vervaeke
1
@JeroenVervaeke 很不幸,那样做效果不佳,TRsponse 将无法被正确推断。使用您的版本,对于调用 makeRequest(GET_TEST, { data: ""}),将会推断出以下内容:makeRequest<IEndpoint<ISomeInterface, IAnotherInterface>, { data: string; }, {}> - Titian Cernicova-Dragomir
1
你是正确的。这是正确的签名:function makeRequest<TData, TResponse>(endPoint: IEndpoint<TData, TResponse>, data: TData): Promise<TResponse> - Jeroen Vervaeke
@JeroenVervaeke 是的,你说得对,那也可以工作 :) - Titian Cernicova-Dragomir

0
你可以通过使用泛型类并将方法绑定到该类来解决你的问题:
export class Endpoint<T, U> {
  constructor(
    private path: string,
    private method: HTTP_METHOD,
    private data: T,
    private response: U
  ) {}

  // your new promise method there
}

-1

您可以在以下代码中找到 meta 部分:

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

由于它表示类型,而不是值。您可以通过使用 typeof 来解决此问题:

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

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

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

此外,TS团队强烈建议使用as作为类型转换运算符,而不是<>
export const GET_TEST: IEndpoint = {
  path: 'api/test',
  method: HTTP_METHOD.GET,
  data: {} as,ISomeInterface
  response: {} as IAnotherInterface
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接