【问题标题】:Typing an array of generic inferred types键入一个泛型推断类型数组
【发布时间】:2020-10-10 17:33:54
【问题描述】:

我正在尝试创建对象数组的类型。此对象的第一个和第二个键需要匹配。例如:

[{ 
  key1: "hi",
  key2: "world"
},{
  key1: 1,
  key2: 2
},{
  key1: true,
  key2: false
}]

这是我想出的,但它并不完全有效。我有一个泛型类型来定义数组中的对象。调用它生成数组类型时,会报错。

type ArrayItem<T> = {
  key1: T,
  key2: T
}

// This raises an error Generic Type ArrayItem requires 1 type argument
type Array = ArrayItem<T>[]

键入这样的嵌套对象的最佳方法是什么(支持类型推断)?

【问题讨论】:

    标签: typescript generics nested type-inference inference


    【解决方案1】:

    处理数组可能很麻烦,即使是泛型类型。这很大程度上取决于初始化数组后您的项目将如何使用。根据您的 sn-ps,我将开始为数组中的每种“类型”条目创建接口,以便为每个不同的属性集获得强类型。

    export interface FooItemType {
      key1: string,
      key2: string,
    }
    
    
    export interface BarItemType {
      key1: boolean,
      key2: boolean,
    }
    

    然后,您可以创建一个映射您之前定义的接口的新类型。

    export type ItemType = BarItemType | FooItemType;
    

    之后,您可以将其声明为简单的ItemType 数组。

    export myArr: ItemType[] = [{ 
      key1: "hi",
      key2: "world"
    },{
      key1: 1,
      key2: 2
    },{
      key1: true,
      key2: false
    }]
    

    虽然这种方法是强类型的,但在您从数组中获取 myArray[i] 项后,它可能会导致一些手动转换。有时我们在考虑其在应用程序中的使用之前就设计了“类型”,因此必须在设计数据结构时将其作为一个整体。

    【讨论】:

      【解决方案2】:

      如果在ArrayItem&lt;T&gt; 中没有T 的可能类型的有限列表,则TypeScript 中没有与Array&lt;ArrayItem&lt;T&gt;&gt; 对应的具体类型。要将这样的东西表示为非泛型类型需要像 existential types 这样的东西,TypeScript 并不直接支持。

      (如果您确实有一个有限列表,例如ArrayItem&lt;string&gt; | ArrayItem&lt;number&gt; | ArrayItem&lt;boolean&gt;,那么您可以像其他答案一样使用联合。)

      在 TypeScript 中最接近这一点的是泛型类型,在推理和编译器警告方面,最好的做法是将其表示为 generic constraint 之类的东西。

      一种方法是编写一个通用帮助函数asMyArray() 接受tuple,编译器将检查元组的每个元素以确保它满足约束条件。一个障碍是{key1: "hi", key2: 2} 确实 满足约束条件,如果你允许像string | number 这样的东西作为T。为了防止编译器愉快地接受所有类型对,我将尝试使其仅从key1 推断T(请参阅microsoft/TypeScript#14829 以查看防止从特定推断站点推断的方法),然后检查key2 匹配:

      type NoInfer<T> = [T][T extends any ? 0 : 1]
      
      const asMyArray = <T extends readonly any[]>(
          x: [...({ [K in keyof T]: { key1: T[K], key2: NoInfer<T[K]> } })]) =>
          x;
      

      泛型类型参数T 是一个元组,对应于传入数组的每个元素的key1 值。传入的数组x 属于mapped tuple type。 &amp; {} 位降低了key2 的推理优先级。 [... ] 位只是提示编译器推断一个元组而不是一个数组(它无法区分不同的元素),让我们测试一下:

      const myArray = asMyArray([{
          key1: "hi",
          key2: "world"
      }, {
          key1: 1,
          key2: 2
      }, {
          key1: true,
          key2: false
      }])
      // const asMyArray: <[string, number, boolean]>(...)
      

      你可以看到T被推断为[string, number, boolean]。这成功了,而下面的 T 以同样的方式推断失败:

      const badArray = asMyArray([{
          key1: "hi", key2: 123 // error!
          // -------> ~~~~
          // number not assignable to string
      }, {
          key1: 1, key2: "world" // error!
          // ----> ~~~~
          // string not assignable to number
      }, {
          key1: true, key2: false
      }]);
      

      看起来像你想要的。好的,希望有帮助;祝你好运!

      Playground link to code

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-24
        • 2023-03-08
        • 1970-01-01
        • 1970-01-01
        • 2022-01-18
        相关资源
        最近更新 更多