我的项目是严格输入的,有很多限制。假设我有一些带有两种方法的类。
Public Sub DDtest()
Dim EDay As Date
Dim ETime As Date
Dim DtgA As Date
EDay = Format(CDate(Replace(Worksheets("Data2020").Range("E2").Value, ".", "/")), "dd-mmm-yyyy")
ETime = Format(Worksheets("Data2020").Range("F2"), "hh:mm:ss")
DtgA = EDay + ETime
Dim EDay2 As Date
Dim ETime2 As Date
Dim DtgB As Date
EDay2 = Format(CDate(Replace(Worksheets("Data2020").Range("E3").Value, ".", "/")), "dd-mmm-yyyy")
ETime2 = Format(Worksheets("Data2020").Range("F3"), "hh:mm:ss")
DtgB = EDay2 + ETime2
Dim result As Date
result = Format(DateDiff("s", DtgA, DtgB) / (60 * 60), "hh:mm:ss")
MsgBox "Date 1:" & DtgA & vbNewLine & "Date 2:" & DtgB & vbNewLine & vbNewLine & DateDiff("s", DtgA, DtgB) / (60 * 60) & vbNewLine & result
End Sub
我想模拟这两个函数,通常我会这样做:class SomeClass {
public someMethod(param1: string, param2: number): string {
return `${param1}: ${param2}`;
}
public otherMethod(param3: string[]): boolean {
return !!param3.length;
}
}
不幸的是,严格的类型+护送规则在很多地方抱怨这种方法。几个例子:
const mock = jest.fn()
我可以明确提供类型:
const mock = jest.fn();
mock.mockReturnValue(34); // no return value error
mock.mock.calls[0][0]; // ESLint: Unsafe member access [0] on an any value.(@typescript-eslint/no-unsafe-member-access)
这是有效的,但很烦人(特别是如果我们更改功能签名等)
为避免这种情况,我可以这样做:
const mock = jest.fn<string, [string, number]>();
mock.mockReturnValue(34); // TS2345: Argument of type '34' is not assignable to parameter of type 'string'
mock.mock.calls[0][0]; // ok
这看起来更好,但是我需要重复很多const mock1 = jest.fn<ReturnType<SomeClass['someMethod']>, Parameters<SomeClass['someMethod']>>();
const mock2 = jest.fn<ReturnType<SomeClass['otherMethod']>, Parameters<SomeClass['otherMethod']>>();
mock1.mockReturnValue(34); // error, TS2345: Argument of type '34' is not assignable to parameter of type 'string'
mock1.mockReturnValue('34'); // ok
mock2.mock.calls[0][1]; // error, TS2493: Tuple type '[string[]]' of length '1' has no element at index '1'.
mock2.mock.calls[0][0]; // ok
,为此可以有一些自动功能。
那是我失败的地方,例如,我尝试通过以下方式重现它:
ReturnType<SomeClass['someMethod']>, Parameters<SomeClass['someMethod']>
但是它得到了:
const typedJestFn = <T, K extends keyof T>() => jest.fn<ReturnType<T[K]>, Parameters<T[K]>>();
const mock4 = typedJestFn<SomeClass, 'someMethod'>();
奇怪的是,mock4本身可以正常工作
PS:
TS2344: Type 'T[K]' does not satisfy the constraint '(...args: any) => any'.
Type 'T[keyof T]' is not assignable to type '(...args: any) => any'.
Type 'T[string] | T[number] | T[symbol]' is not assignable to type '(...args: any) => any'.
Type 'T[string]' is not assignable to type '(...args: any) => any'.
答案 0 :(得分:1)
该问题的问题在于,首先我们创建一个通用类型T
,然后从该K
中获取一个密钥T
。使用T[K]
,我们尝试访问该成员,该成员可以是任何类型(不受模板类型限制)。
因此,尽管很难从类中过滤函数(方法),但事实证明我们根本不需要它。我们只需要任何函数,T
可以只是一个函数。
这是我最终得到的解决方案:
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const typedJestFn = <T extends (...args: any) => any>() => jest.fn<ReturnType<T>, Parameters<T>>();
效果不佳,有any
,但是它没有任何影响,只是通知T应该是函数类型。