简体   繁体   English

返回dict键的Typescript类型推断基于提供的参数

[英]Typescript type inference of return dict keys based on supplied parameters

I have the following files: 我有以下文件:

types.ts types.ts

import * as Promise from 'bluebird';

export interface ApiSpec {
    [apiReq: string]: (...args: any[]) => {
        url: string;
        contentType?: string;
        query?: {
            [key: string]: any;
        };
        method?: string;
    };
}

export type ApiRequest = {
    [T in keyof ApiSpec]: (...args: any[]) => Promise<any>;
};

Api.ts Api.ts

import {ApiSpec, ApiRequest} from './types';
import * as _ from 'lodash';

export default function createApi(apiSpec: ApiSpec, concurrent: boolean = false): ApiRequest {
    return _.mapValues(apiSpec, (fn, name) => {
        return function(...args) {
            const requestSpec = fn.apply(null, args);
            requestSpec.which = name;
            requestSpec.url = `http://localhost:8989/api${requestSpec.url}`;
            // request is a function doing the API request and returning a bluebird promise
            return request(requestSpec, concurrent);
        }
    });
}

main.ts main.ts

import createApi from './Api';

// usually defined in a separate file
const ApiSpec = {
    fetchData: (start: Date, end: Date) => {
        return {
            url: `/fetchData?start=${start}&end=${end}`
        };
    }
};
const Api = createApi(ApiSpec);

Api.fetchData(new Date(), new Date()).then(res => {
    // do something with result
})

Is it possible in typescript to have type completion for my Api variable? 打字稿中是否可以为我的Api变量进行类型完成? I would like to be able to know which functions are available in my API and most importantly the parameters of each API call without having to look at the file where the API spec is defined. 我希望能够知道我的API中可用的功能,最重要的是每个API调用的参数,而无需查看定义API规范的文件。 However, just using [T in keyof ApiSpec] in the types cannot infer the exact keys of the API spec I'm passing to createApi . 但是,在类型中仅使用[T in keyof ApiSpec]无法推断出我传递给createApi的API规范的确切键。 Is this somehow possible in typescript? 这在打字稿中是否有可能?

Note: I'm using version 2.3.4 and cannot update to the latest typescript version at the moment 注意:我使用的是2.3.4版,目前无法更新到最新的打字稿版本

You need to use a generic type parameter to capture the actual type passed in to createApi and map that in ApiRequest instead of the generic ApiSpec . 您需要使用泛型类型参数来捕获传递给createApi的实际类型,并将其映射到ApiRequest而不是通用ApiSpec ApiSpec can be used as the type constraint for the type parameter. ApiSpec可以用作type参数的类型约束。

export interface ApiSpec {
    [apiReq: string]: (...args: any[]) => {
        url: string;
        contentType?: string;
        query?: {
            [key: string]: any;
        };
        method?: string;
    };
}

export type ApiRequest<T extends ApiSpec> = {
    [P in keyof T]: (...args: Parameters<T[P]>) => Promise<any>;
};



export default function createApi<T extends ApiSpec>(apiSpec: T, concurrent: boolean = false): ApiRequest<T> {
    return null!; // implementation 
}
// usually defined in a separate file
const ApiSpec = {
    fetchData: (start: Date, end: Date) => {
        return {
            url: `/fetchData?start=${start}&end=${end}`
        };
    }
};
const Api = createApi(ApiSpec);

Api.fetchData(new Date(), new Date()).then(res => {
    // do something with result
})

Note I also added the Parameters<T[P]> in order to preserve argument types in the resulting object. 注意我还添加了Parameters<T[P]> ,以便在结果对象中保留参数类型。

Edit For the version of typescript you are using (2.3), we don't have conditional types or tuples in rest parameters, so there is no way to map the function parameters in a type safe way unfortunately. 编辑对于您正在使用的打字稿版本(2.3),我们在rest参数中没有条件类型或元组,因此无法以类型安全的方式映射函数参数。 The best we can do is : 我们能做的最好的事情是:

export type ApiRequest<T extends ApiSpec> = {
    [P in keyof T]: (...args: any[]) => Promise<any>;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM