从兄弟中推断类型

时间:2018-03-01 20:30:26

标签: typescript

我正在使用以下界面编写一些中间件

interface Config {
    callApi<P> (api: ApiClient): Promise<P>,
    transformResponse?(payload: P): any
}

从上面可以看出,配置采用callApi函数调用远程APi并返回基于promise的结果,然后选择将接收有效负载的transformResponse,并对其应用转换。关键部分是transformResponse函数应根据callApi调用的返回类型推断有效负载的类型

问题是上述内容无效,因为P内的transformResponse类型无法达到callApi函数的相同变量。

有没有办法完成上述任务,而无需像这样传递API响应类型

interface Config<ApiResponse> {
    callApi (api: ApiClient): Promise<ApiResponse>,
    transformResponse?(payload: ApiResponse): any
}

使用示例

const callCreateComment: Config = {
  callApi (api) => api.createComment(),
  transformResponse(payload) => ({ ...payload // infer the return type of the `api.createComment()` call })
}

1 个答案:

答案 0 :(得分:2)

好的,我想我明白了你想要的,就是写出callApi()方法,然后让TypeScript使用该方法的返回类型来约束transformResponse()方法的参数。我无法弄清楚如何使用对象文字进行推理。看起来,通用ApiResponse参数尚未及时解析,无法将参数类型约束为transformResponse()

我可以推断出工作的方法是将对象文字分成两部分并使用一个函数将这些部分作为参数并将它们放在一起。这使我们可以利用left-to-right inference进行上下文类型的函数参数。为了向您展示它可能更有意义:

我将为您假设这些定义,因为您没有指定它们:

interface Comment {
    something: string; // who knows
}
interface ApiClient {
    createComment(): Promise<Comment>;
}

我将为Config的方法提供一些类型别名,以便我可以重复使用它们:

type CallApi<R> = (api: ApiClient) => Promise<R>;
type TransformResponse<R> = (payload: R) => any;

最后,这是您的Config<R>,它实际上与R而不是ApiResponse的(已修改)版本相同:

interface Config<R> {
    callApi: CallApi<R>,
    transformResponse?: TransformResponse<R>
}

所以这是推理工作的功能:

const buildConfig = <R>(
    callApi: CallApi<R>, 
    transformResponse?: TransformResponse<R>
): Config<R> => ({ callApi, transformResponse });

buildConfig()函数有两个参数。第一个是CallApi<R>,第二个是TransformResponse<R>。函数参数的从左到右的上下文类型推断意味着它将从第一个参数解析R,然后在第二个参数的上下文类型中使用它。像这样:

const callCreateComment = buildConfig(
    (api) => api.createComment(),  // R is inferred as Comment
    (payload) => ({ ...payload })  // payload is now constrained
);

您会注意到,当您输入时,payload的上下文类型将被推断为Comment。而且callCreateComment的输入为Config<Comment>,您无需根据需要在该功能中的任何位置指定Comment

Playground link

希望有所帮助。祝你好运!