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

X4V*_*V18 3 generics type-inference typescript

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

function doSomething <T>(values: Whatever[], getter: (whatever: Whatever) => T): T[] {
  return values.map(value => getter(value));
}
Run Code Online (Sandbox Code Playgroud)

然后我想让 getter 函数成为可选的,并为此使用默认值。问题就在那时发生了。

function doSomething <T>(values: Whatever[], getter: (whatever: Whatever) => T = val => val): T[] {
  return values.map(value => getter(value));
}
Run Code Online (Sandbox Code Playgroud)

所以现在我收到错误消息:

错误:(18, 47) TS2322:类型“(val:Whatever)=>Whatever”不可分配给类型“(whatever:Whatever)=>T”。类型“Whatever”不可分配给类型“T”。

你知道我为什么会收到这个错误吗?

先感谢您,

(下面的示例不是我的真实代码,但这更清楚地描述了我的问题)

我正在使用打字稿 2.7.2

art*_*tem 5

问题是默认 getter 函数的返回类型是Whatever,但doSomething声明要求 getter 必须返回TT是泛型类型参数,它可以是任何东西,不保证WhateverT. TypeScript 编译器看不到,当提供默认值时,T没有必要,并且返回类型doSomethingWhatever[]。但是您可以使用以下重载声明来表达它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));
}
Run Code Online (Sandbox Code Playgroud)

更新以解决已澄清的问题

我想避免返回“Whatever | T”,因为每次调用此函数时,我都必须检查响应类型(Whatever 或 T)。

当您调用此函数时,仅考虑两个重载签名,TypeScript 在 doSomething(). 事实上,实现返回类型可以简单地声明为any,就像在重载文档示例中所做的那样- 它仅用于对实现进行类型检查,并且实现通常足够明显,因此更严格的类型不会提供太多好处。

我想编写代码来获取 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[]
}
Run Code Online (Sandbox Code Playgroud)