Typescript:函数返回类型取决于输入函数返回类型

问题描述 投票:2回答:2

我有一个函数,在参数中采用另一个函数。我想返回一个通用接口,该接口由参数中传递的函数的返回类型配置。

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

typescript generics type-inference
2个回答
4
投票

问题是默认getter函数的返回类型是Whatever,但doSomething声明要求getter必须返回TT是通用类型参数,它可以是任何东西,但不能保证WhateverT兼容。 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[]
}

0
投票

如果你想要一个没有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[]代替返回一个副本。

© www.soinside.com 2019 - 2024. All rights reserved.