我正在创建一个模拟实用程序,所以我有这个方法,它接受一个对象和该对象上映射到函数的键,然后记录可能的输入和输出:
function mockHook<
OBJECT extends Record<string, any>,
METHOD_NAME extends MethodKeys<OBJECT>,
METHOD extends AnyFunction = OBJECT[METHOD_NAME],
>(
obj: OBJECT,
methodName: METHOD_NAME,
mockedConditions: Map<Parameters<METHOD>, Partial<ReturnType<METHOD>>>
)
使用这些辅助类型:
type AnyFunction = (...args: any[]) => any;
/**
* Type to extract only entries on T whose keys are strings and values are methods
*/
type MethodKeys<T> = {
[K in keyof T]: K extends string ? (T[K] extends AnyFunction ? K : never) : never;
}[keyof T];
我有一个非常常见的用法,其中对象具有“默认”键,因此我想创建一个辅助方法,该方法将使用“默认”作为方法名称,同时强制执行类型。
我尝试这样做:
export function mockHookDefault<
OBJECT extends { default: AnyFunction },
METHOD extends OBJECT['default'] = OBJECT['default'],
>(obj: OBJECT, mockedConditions: Map<Parameters<METHOD>, Partial<ReturnType<METHOD>>>) {
return mockHook(obj, 'default', mockedConditions);
}
但是使用“默认”键时出现错误:
TS2345: Argument of type string is not assignable to parameter of type MethodKeys<OBJECT>
奇怪的是,如果在mockHookDefault内部我这样做:
const a: MethodKeys<OBJECT> = 'default';
const b: MethodKeys<{ default: () => {} }> = 'default';
a 抛出异常,而 b 则不抛出异常(TS2322:类型字符串不可分配给类型 MethodKeys)
对我来说,这似乎是相同的类型,那么为什么打字稿不允许这样做,我可以在不使用“as MethodKeys”的情况下修复它吗?
由于某种原因,OBJECT 的键和它的 MethodKey 不匹配。
我认为mockHook专注于对象方法,所以你也关注它们,使OBJECT更加严格并放松它在函数参数上:
type AnyFunction = (...args: any[]) => any;
/**
* Type to extract only entries on T whose keys are strings and values are methods
*/
type MethodKeys<T> = {
[K in keyof T]: K extends string ? (T[K] extends AnyFunction ? K : never) : never;
}[keyof T];
function mockHook<
OBJECT extends Record<string, AnyFunction>,
METHOD_NAME extends keyof OBJECT,
METHOD extends AnyFunction = OBJECT[METHOD_NAME],
>(obj: OBJECT & Record<string, any>, methodName: METHOD_NAME, mockedConditions: Map<Parameters<METHOD>, Partial<ReturnType<METHOD>>>) {
}
export function mockHookDefault<
OBJECT extends { default: AnyFunction },
METHOD extends OBJECT['default'] = OBJECT['default'],
>(obj: OBJECT, mockedConditions: Map<Parameters<METHOD>, Partial<ReturnType<METHOD>>>) {
return mockHook(obj, 'default', mockedConditions);
}