我有一个函数,在参数中采用另一个函数。我想返回一个通用接口,该接口由参数中传递的函数的返回类型配置。
function doSomething <T>(values: Whatever[], getter: (whatever: Whatever) => T): T[] {
return values.map(value => getter(value));
}
然后我想让getter函数可选,并为此使用默认值。问题发生在那个时候。
function doSomething <T>(values: Whatever[], getter: (whatever: Whatever) => T = val => val): T[] {
return values.map(value => getter(value));
}
所以现在我得到并且错误地说:
错误:(18,47)TS2322:输入'(val:Whatever)=>无论'不能分配给''(无论如何:Whatever)=> T'。输入'Whatever'不能指定为'T'。
你知道我为什么会收到这个错误吗?
先感谢您,
(下面的例子不是我的真实代码,但这更清楚地描述了我的问题)
我正在使用打字稿2.7.2
问题是默认getter函数的返回类型是Whatever
,但doSomething
声明要求getter必须返回T
。 T
是通用类型参数,它可以是任何东西,但不能保证Whatever
与T
兼容。 TypeScript编译器没有看到提供默认值时,T
不是必需的,doSomething
的返回类型是Whatever[]
。但你可以用doSomething
的这些重载声明来表达它:
function doSomething<T>(values: Whatever[], getter: (whatever: Whatever) => T): T[];
function doSomething(values: Whatever[]): Whatever[];
// the implementation must be compatible with both variants
function doSomething<T>(values: Whatever[], getter: (whatever: Whatever) => T | Whatever = val => val ): (T | Whatever)[] {
return values.map(value => getter(value));
}
更新以解决澄清的问题:
我想避免返回“Whatever | T”,因为每次我将调用此函数时,我将不得不检查响应类型(Whatever或T)。
当您调用此函数时,只考虑两个重载的签名,TypeScript在doSomething()
的调用站点执行重载解析时不使用实现签名。事实上,实现返回类型可以简单地声明为any
,因为它在重载documentation examples中完成 - 它仅用于类型检查实现,并且实现通常很明显,因此更严格的类型不会提供太多好处。
我想编写代码来获取getter函数的返回类型并用作T.
如果在调用doSomething
时省略泛型参数,编译器将从T
返回类型推断getter
。我认为以下示例可以满足您的需求:
interface Whatever { w: string };
function doSomething<T>(values: Whatever[], getter: (whatever: Whatever) => T): T[];
function doSomething(values: Whatever[]): Whatever[];
function doSomething<T>(values: Whatever[], getter: (whatever: Whatever) => T | Whatever = val => val ): (T | Whatever)[] {
return values.map(value => getter(value));
}
function example() {
const getter1 = (whatever: Whatever) => whatever.w; // returns string
const getter2 = (whatever: Whatever) => whatever.w.length; // returns number
const values: Whatever[] = [];
const r0 = doSomething(values); // const r1: Whatever[]
const r1 = doSomething(values, getter1); // const r1: string[]
const r2 = doSomething(values, getter2); // const r2: number[]
}
如果你想要一个没有getter的默认行为,我认为有一个默认的getter只是试图强制转换是完全可以的:val => val as T
function doSomething <T>(values: Whatever[], getter: (whatever: Whatever) => T = val => val as T): T[] {
return values.map(getter);
}
而且,在“编译时”期间,Typescript只是类型安全的语法糖,这意味着:'尽量获得没有任何映射的价值'。因此,如果您认为这样,如果没有给出getter,这意味着它实际上不会更改数组的值。根据用例你可能会这样做
function doSomething <T>(values: Whatever[], getter?: (whatever: Whatever) => T): T[] {
if (getter === undefined) { return values as T[]; }
return values.map(value => getter(value));
}
并跳过map()除了复制数组之外什么也不做,如果那是你想要的那样:return [...values] as T[]
代替返回一个副本。