【问题标题】:Explicit return type based on arguments基于参数的显式返回类型
【发布时间】:2020-12-10 05:06:44
【问题描述】:

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

函数-

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 函数中需要做什么才能根据参数导出显式返回类型。为了清楚起见,我不担心返回类型的值,只担心获取显式键。

【问题讨论】:

    标签: typescript typescript-typings typescript-generics


    【解决方案1】:

    如果你想让它工作,你需要 objectFromArray() 成为 K 类型中的 string literalkey 元素的 key 属性中的 arr

    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;
    }
    

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

    返回类型{ [P in K]: true } 是一个mapped type,它为K 中的每个字符串文字类型提供一个具有true 值属性的对象。 (您也可以使用Record utility type 来提供等效的Record&lt;K, true&gt;)。由于{} 不是此类型的有效值,因此您需要type assertion 来告诉编译器将obj 视为{ [P in K]: true } 类型。


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

    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 具有true 类型的abc 属性,根据需要。

    Playground link to code

    【讨论】:

      猜你喜欢
      • 2021-11-10
      • 1970-01-01
      • 2023-03-30
      • 2022-11-04
      • 1970-01-01
      • 1970-01-01
      • 2020-10-27
      • 2019-06-07
      • 1970-01-01
      相关资源
      最近更新 更多