当对象类型是通用类型时,Typescript 推断方法键不起作用[重复]

问题描述 投票:0回答:1

我正在创建一个模拟实用程序,所以我有这个方法,它接受一个对象和该对象上映射到函数的键,然后记录可能的输入和输出:

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”的情况下修复它吗?

这是一个演示该问题的 ts 游乐场

typescript type-inference
1个回答
0
投票

由于某种原因,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);
}
© www.soinside.com 2019 - 2024. All rights reserved.