【问题标题】:Typescript Map of generics泛型的打字稿地图
【发布时间】:2020-10-18 08:38:30
【问题描述】:

我试图让ObjectType 中的每个Field 拥有自己的泛型,因此每个字段的resolve fn 必须返回type 属性中定义的类型。

type Scalars = {
  ID: string;
  Int: number;
  Float: number;
  String: string;
  Boolean: boolean;
};

type Field<T extends keyof Scalars> = {
  type: T,
  resolve: () => Scalars[T];
}

type ObjectType<T extends keyof Scalars> = {
  [key: string]: Field<T>
}

const objectType = <T extends keyof Scalars>(config: ObjectType<T>): any => 'todo';

objectType({
  id: {
    type: 'Int',
    // type of `resolve` is `() => (string | number)`, should be `() => number`
    resolve: () => '123',
  },
  name: {
    type: 'String',
    // should be `() => string`
    resolve: () => 123,
  },
});

在调查了其他一些 SO 问题后,我在https://stackoverflow.com/a/51547767/11042710 中找到了一个几乎可以解决我的问题的解决方案

这是我尝试上述建议的 TS 游乐场 TS playground.

但是当我尝试将infer P 类型传递给extends keyof Scalars 的泛型时它失败了

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    看起来您的Field&lt;..&gt; 类型可以像这样形成discriminated union

    type Fields = { [K in keyof Scalars]: Field<K> }[keyof Scalars];
    

    这里Fields的类型等价于

    type Fields = Field<"ID"> | Field<"Int"> | Field<"Float"> | 
      Field<"String"> | Field<"Boolean">
    

    联合中的所有术语都有一个公共的type 字段,该字段是字符串文字类型,可用于区分它们。这很好,因为这意味着您的objectType() 方法可以减少很多通用的环跳,因为config 属性值可以限制为特定类型Fields

    const objectType = <T extends Record<keyof T, Fields>>(config: T): any => 'todo';
    

    现在我们所做的只是将config 约束为具有任意键(Record&lt;keyof T, ...&gt;)且其值全部为Fields 的对象。让我们看看它是否有效。这是预期用途:

    objectType({
      id: {
        type: 'String',
        resolve: () => "123",
      },
      ide: {
        type: 'Int',
        resolve: () => 123,
      },
    });
    

    当你做错时会发生这种情况:

    objectType({
      id: { // error! number is not assignable to string
        type: 'String',
        resolve: () => 123,
      },
      ide: { // error! string is not assignable to boolean
        type: 'Boolean',
        resolve: () => "123",
      },
    });
    

    这些是您期望的错误,对吧?

    Playground link to code

    【讨论】:

    • 确实有效!但我可能应该给出完整的上下文,因为类型有点复杂。 type 属性不能只采用标量,它还可以采用另一个 ObjectType,如果它采用 ObjectType,则解析函数应该返回一个我传递给 ObjectType 的泛型。这是到操场 bit.ly/3dDlNsJ 的缩短链接(SO 抱怨缩短的链接和 TS 操场链接太长,无法发表评论)
    • 我并不特别倾向于涉足该代码,因为 Field 定义是一组繁琐的嵌套条件类型。如果你把它做得更小,我会看看。
    • 公平,我想这次我会提供完整的背景信息,但这没有必要,这是新的游乐场链接 bit.ly/2T6hWuH
    • this 是否适用于您的用例? (还没有看到你的新链接)
    • 这不是因为resolvetype 是ObjectType 时返回的值不是其字段的类型,而是将传递给ObjectType 的泛型。当没有传递泛型时,也许它可以默认为字段的类型,这就是一些库的做法,但消费者能够将任意类型传递给 ObjectType 非常重要,这两者都将用作第一个参数当此 ObjectType 用作 type 时,ObjectType 字段的解析 fn AND 作为字段 resolve fn 的返回类型。
    猜你喜欢
    • 2015-11-27
    • 1970-01-01
    • 2021-11-26
    • 1970-01-01
    • 2018-11-17
    • 2021-12-20
    • 2022-08-21
    • 1970-01-01
    • 2023-02-22
    相关资源
    最近更新 更多