下面是一个makeSafe函数,它在下面的测试中被调用。
import { expect, it } from 'vitest';
import { Equal, Expect } from '../helpers/type-utils';
const makeSafe =
<Args extends string | number, R>(func: (...args: Args[]) => R) =>
(
...args: Args[]
):
| {
type: 'success';
result: R;
}
| {
type: 'failure';
error: Error;
} => {
try {
const result = func(...args);
return {
type: 'success',
result,
};
} catch (e) {
return {
type: 'failure',
error: e as Error,
};
}
};
it("Should properly match the function's arguments", () => {
const func = makeSafe((a: number, b: string) => {
return `${a} ${b}`;
});
// @ts-expect-error
func();
// @ts-expect-error
func(1, 1);
func(1, '1');
});
typescript推断args为(字符串|number)[],因此我得到了这个错误
ts-error
Argument of type '(a: number, b: string) => string' is not assignable to parameter of type '(...args: (string | number)[]) => string'.
Types of parameters 'a' and 'args' are incompatible.
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.(2345)
但是使用下面的makeSafe函数的类型定义,typescript将args推断为文字元组[a:number,b:string],所以我没有得到任何错误,测试通过
import { expect, it } from 'vitest';
import { Equal, Expect } from '../helpers/type-utils';
const makeSafe =
<Args extends (string | number)[], R>(func: (...args: Args) => R) =>
(
...args: Args
):
| {
type: 'success';
result: R;
}
| {
type: 'failure';
error: Error;
} => {
try {
const result = func(...args);
return {
type: 'success',
result,
};
} catch (e) {
return {
type: 'failure',
error: e as Error,
};
}
};
这两种解决方案的唯一区别是typescript如何推断参数args,为什么typescript要这样做?
1条答案
按热度按时间xzlaal3s1#
当您定义
Args extends string | number
并将其用作...args: Args[]
时,它实际上可以按预期工作。如果你传递(a: number, b: string)
,Args
计算为string | number
,你得到string | number[]
。所以基本上你的泛型只计算数组的一个元素,而不是整个数组。然而,在第二种情况下,您期望的是一个extends string | number
的元素数组,这使编译器能够完全理解...args
的类型。