首页 > 解决方案 > 基于参数的显式返回类型

问题描述

给定一个函数,它接受一个对象数组,并返回一个对象,其键都对应于参数中每个对象的属性......似乎应该有一种方法来获得更明确的返回类型。

功能-

function objectFromArray(arr: { key: string }[]) {
    let obj: {[k: string]: true} = {};
    for (let {key} of arr) {
        obj[key] = true;
    }
    return obj;
}

如果我运行以下

let myArray = [{key: 'a'}, {key: 'b'}, {key: 'c'}];
let myObj = objectFromArray(myArray);

那么类型myObj

let myObj: {
    [k: string]: true;
}

但我觉得存在足够的信息,以便打字稿推断出的类型myObj实际上是

let myObj: {
    a: true;
    b: true;
    c: true;
}

我的问题是在函数中需要做什么objectFromArray才能根据参数派生显式返回类型。为了清楚起见,我不担心返回类型的值,只担心获取显式键。

标签: typescripttypescript-typingstypescript-generics

解决方案


如果你想让它工作,你需要objectFromArray()成为元素属性中字符串文字值类型的通用函数:Kkeyarr

function objectFromArray<K extends string>(arr: readonly { key: K }[]) {
  let obj = {} as { [P in K]: true }; // have to assert this because it's not true yet
  for (let { key } of arr) {
    obj[key] = true;
  }
  return obj;
}

readonlyinreadonly { key: K }[]只是意味着我们并不特别要求传入的数组是可变的。这为输入提供了更多的余地,我们稍后会需要。

返回类型{ [P in K]: true }是一个映射类型,它trueK. (您也可以使用Record实用程序类型来提供等价的Record<K, true>)。由于{}is 不是此类型的有效值,因此您需要一个类型断言来告诉编译器将obj其视为 type { [P in K]: true }


然后,当您创建时myArray,编译器的默认行为是将其类型扩展为Array<{key: string}>,完全忘记字符串文字类型"a","b""c"。为了防止这种情况,您可以使用const断言

let myArray = [{ key: 'a' }, { key: 'b' }, { key: 'c' }] as const;

/* let myArray: readonly [{
    readonly key: "a";
}, {
    readonly key: "b";
}, {
    readonly key: "c";
}] */

注意const断言是如何创建myArray一个readonly数组的,这就是为什么放宽函数的输入类型是有用的。既然编译器已经足够了解 了myArray,让我们调用objectFromArray()

let myObj = objectFromArray(myArray);
/* let myObj: {
    a: true;
    b: true;
    c: true;
} */

成功! myObj根据需要,已知具有abc类型的属性true

Playground 代码链接


推荐阅读