定义具有正确类型的对象数组

时间:2018-12-24 17:22:52

标签: typescript

Typescript的新手,我有一个关于键入对象数组的快速问题。 现在就可以了:

const my_array = [{
    foo: "hello",
    bar: "Typescript"
  },
  {
    foo: "goodbye",
    bar: "JavaScript"
  }
];

默认情况下,它将推断类型为

的my_array
{foo:string; bar:string;}[]

我的要求:我希望输入更准确的信息,例如:

{foo: "hello" | "goodbye"; bar: // value according to foo }

我还希望有一个 DRY 解决方案,并且只定义一次我的foobar值以提高可维护性

3 个答案:

答案 0 :(得分:2)

您可以为每种记录类型定义类型:

type Alpha = {"foo": "alpha", "bar": number}
type Beta = {"foo": "beta", "bar": string}

然后,您可以定义一个数组,该数组是AlphaBeta(称为联合类型)的列表

let arr: (Alpha | Beta)[] = some_array();

遍历数组时,TypeScript将字段的类型识别为

for (let el of arr) {
    // el.foo is "alpha" | "beta"
    // el.bar is number | string

但是,如果您检查.foo标记,TypeScript将缩小.bar的类型,因为它实际上知道每个元素都是AlphaBeta

    if (el.foo == "alpha") {
        // el.bar is number
    } else {
        // el.bar is string
    }
}

答案 1 :(得分:2)

当这些值包含为数组元素或对象属性时,将这些值哄骗到编译器以推断文字类型是很棘手的。这是一种解决方法:

type Narrowable = string | number | boolean | object | {} | null | undefined | void;
const tupleOfNarrowObjects = 
  <V extends Narrowable, O extends { [k: string]: V }, T extends O[]>(...t: T) => t;
const my_array = tupleOfNarrowObjects(
  {
    foo: "hello",
    bar: "Typescript"
  }, {
    foo: "goodbye",
    bar: "JavaScript"
  }
);

如果您这样做,my_array现在将被推断为以下类型:

const my_array: [{
    foo: "hello";
    bar: "Typescript";
}, {
    foo: "goodbye";
    bar: "JavaScript";
}]

尽可能地狭窄:一个由字符串文字组成的对象的元组。因此,编译器知道my_array[0].foo"hello"。而且,如果您遍历my_array,则编译器会将每个元素都视为discriminated union

工作原理:

  • Narrowable类型与unknown基本相同,不同之处在于编译器将其视为包含stringnumber的并集。如果您有一个通用类型参数V extends N,其中约束Nstringnumber或包含它们的并集,则V将被推断为文字输入是否可以。

  • 通常,将类型参数O推断为对象类型时,它不会将属性类型的范围缩小为文字。但是,如果将O约束为一种索引签名类型,而其值类型可以缩小为文字,例如{ [k: string]: V },则它将。

  • 最后,当使用约束为数组类型的泛型类型的rest参数时,编译器将尽可能推断该参数的元组类型。

将所有这些放在一起,如果可能的话,以上tupleOfNarrowObjects会将其参数推断为文字属性对象的元组。这很丑陋(单个参数有三个类型的参数),但它的工作原理是:您不必重复自己。

希望对您有帮助。祝你好运。

答案 2 :(得分:0)

从 3.7.5 版本开始的当前 Typescript 实现,为推导编译时常量窄参数类型提供了有限的支持,但特定的构造允许它:

type Narrowable = "" | 0 | true | false | symbol | object | undefined | void | null | {} | [Narrowable] | { [k in keyof any]: Narrowable }

function gen<T extends Narrowable>(x: T): T { return x };

const f = gen(["www", 1,2,3,[1,2,3,[5,"qqq"],"str"],4, {a:5,b:{c:{a:54,b:"www"}}}])