我有以下文件:
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
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
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
})
在打字稿中是否可以为我的Api
变量完成打字?我希望能够知道我的API中可用的功能,最重要的是,每个API调用的参数都无需查看定义API规范的文件。但是,仅在类型中使用[T in keyof ApiSpec]
不能推断出我要传递给createApi
的API规范的确切键。这在打字稿中有可能吗?
注意:我正在使用2.3.4版本,目前无法更新到最新的打字稿版本
答案 0 :(得分:3)
您需要使用通用类型参数来捕获传递给createApi
的实际类型,并将其映射到ApiRequest
中,而不是通用ApiSpec
中。 ApiSpec
可以用作类型参数的类型约束。
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
})
注意,我还添加了Parameters<T[P]>
以便在结果对象中保留参数类型。
修改 对于您正在使用的Typescript版本(2.3),我们在rest参数中没有条件类型或元组,因此不幸的是,无法以类型安全的方式映射函数参数。我们能做的最好的是:
export type ApiRequest<T extends ApiSpec> = {
[P in keyof T]: (...args: any[]) => Promise<any>;
};