我正在尝试创建一种类型安全的GraphQL数据获取方法。我使用服务器上生成的类型,并希望选择在这些类型上定义的属性的子集作为结果类型。
从服务器生成的代码如下
export interface Dream {
id: number;
title?: string;
}
export interface IQuery {
dream(id: number): Dream | Promise<Dream>;
}
检索数据的功能:
function doQuery<
QName extends keyof IQuery,
QParams extends Parameters<IQuery[QName]>,
R extends Partial<ReturnType<IQuery[QName]>>
>(queryName: QName, params: QParams, resultSelector: R): R {
return {} as R; // stub
}
还有一个实用程序类,可以在运行时使用“类型”
class types {
static number: number;
static string: string;
static boolean: boolean;
}
例如,当调用函数时
const result = doQuery("dream", [2], {
title: types.string
});
结果类型正确推断为
const result: {
title: string;
}
当我打电话时
const result = doQuery("dream", [2], {
nonExisting: types.string,
});
编译器抛出Object literal may only specify known properties, and 'nonExisting' does not exist in type 'RecursivePartial<Dream>
,这正是我想要的。
但是,当使用调用该函数时
const result = doQuery("dream", [2], {
id: types.number,
nonExisting: types.string,
});
编译器说可以,我不希望这样。我希望编译器以与以前相同的方式抛出。
结果类型应始终与resultSelector类型相同。
到目前为止,在我已经尝试过的代码中,尚未处理查询结果为Dream | Promise<Dream>
的可能性。我相信条件类型应该可以做到这一点。
“部分”部分也是我能想到的最好的部分,但实际上应该是ReturnType<IQuery[QName]> extends R
而不是相反的方式,我不知道该如何在Typescript中表达。
是否有可能在Typescript的当前水平上实现我正在寻找的约束?如果是这样,怎么办?如果没有,为什么不呢?
谢谢。
答案 0 :(得分:0)
我设法使其适用于
type Awaited<T> = T extends { then(onfulfilled: (value: infer U) => any): any }
? U
: T extends { then(...args: any[]): any }
? never
: T;
和
type Subset<S, F> = { [key in keyof S]: key extends keyof F ? F[key] : never };
和
function doQuery<
QName extends keyof IQuery,
QParams extends Parameters<IQuery[QName]>,
R extends Subset<R, Awaited<ReturnType<IQuery[QName]>>>
>(queryName: QName, params: QParams, resultSelector: R): R {
return {} as R;
}