繁体   English   中英

有没有办法让 TypeScript 根据调用 arguments 推断函数返回值的类型?

[英]Is there any way to have TypeScript infer the type of a function's return value based on the call arguments?

我正在设置一个 function 将从我的数据库中检索数据。 它将键字符串作为参数,并根据键返回不同的数据类型。

我的目标是让 TypeScript 根据作为参数传递的键推断将返回的类型。

这是我尝试过的:

interface Fruits { names: string[] }
interface Employees { ages: number[] }

function getData(key: "fruits" | "employees") {
  if (key === "fruits") {
    // fetch data for /fruits and return it, specifying its type
    return { names: ["apple", "orange", "kiwi"] } as Fruits;
  }

  // fetch data for /employees and return it, specifying its type
  return { ages: [30, 50, 19 ] } as Employees;
}

const fruits = getData("fruits"); 
// ...should infer that the returned value will be of type 'Fruits'
        
const fruitNames = fruits.names; 
// ...fails to infer type. Thinks fruits is of type (Fruits | Employees)

最后一行给出警告,因为 TypeScript 无法推断在调用 getData 时使用键“fruits”将始终返回 Fruits 类型的值(反过来,它具有属性“names”)。

当然,我也可以通过像这样对 getData 的调用进行类型转换来消除错误 go :

const fruits = getData("fruits") as Fruits;

但是,在我看来,这违背了首先使用 TypeScript 的目的,因为我的代码再次变得非常容易出错。 例如,如果我进行了错误的类型转换,技术上不正确的代码不会给出任何警告:

const fruits = getData("fruits") as Employees;
const nonexistent = fruits.ages; 
// TS won't complain about any accesses to the non-existent property 'ages' 
// because I made the wrong typecasting

我的目标是,使用 getData function 的人提前知道,多亏了 TypeScript 的 IntelliSense,一旦他们提供了用于查询数据的“密钥”字符串,他们就会立即返回数据类型。 调用 function 时,不必手动对函数的返回值类型进行类型转换。

在 getData 内部,任何类型转换、使用 generics 或任何其他类型都可以。 但是,除此之外,给 function 一个有效的键参数应该足以让 TypeScript 推断出正确的返回类型。

有什么办法可以做到这一点?

另一种方法是为每个具有适当类型的返回值的键声明function 重载 您的实现将键入key及其所有可能的值,并具有一个返回类型,该类型是所有可能返回的联合。 那看起来像:

interface Fruits { names: string[] }
interface Employees { ages: number[] }

function getData(key: "fruits"): Fruits;
function getData(key: "employees"): Employees;

function getData(key: "fruits" | "employees"): Fruits | Employees {
  if (key === "fruits") {
    // fetch data for /fruits and return it
    return { names: ["apple", "orange", "kiwi"] };
  }

  // fetch data for /employees and return it
  return { ages: [30, 50, 19 ] };
}

其实有好几种方法,这里有一种方法

interface Fruits {
    names: string[];
}
interface Employees {
    ages: number[];
}

interface DataMap {
    fruits: Fruits;
    employees: Employees;
}

function getData<T extends keyof DataMap>(key: T): DataMap[T] {
if (key === "fruits") {
    // fetch data for /fruits and return it, specifying its type
    return { names: ["apple", "orange", "kiwi"] } as DataMap[T];
}

// fetch data for /employees and return it, specifying its type
    return { ages: [30, 50, 19] } as DataMap[T];
}

const fruits = getData("fruits"); // knows it's a Fruits
const fruitNames = fruits.names; // works

我们制作了一个辅助类型,用于将 map 字符串转换为类型,并使用此泛型来捕获 T 以便我们可以在返回类型中使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM