【问题标题】:Define TypeScript type based on generic type基于泛型类型定义 TypeScript 类型
【发布时间】:2021-03-26 15:33:25
【问题描述】:

让我们在 TypeScript (4.0.5) 中创建带有列 data 的 JSON 类型的 SQL 数据库表和此枚举:

enum EContentType {
  NOTHING,
  IMAGE,
  VIDEO
}

根据ContentType,我将不同的 JSON 模式保存到我的数据库中的data 列中。

例子:

  • 对于IMAGE,保存{"path": "/foo/bar", "type": "jpeg"}
  • 对于VIDEO,保存{"path": "/foo/bar", "length": 60}

是否可以使用泛型为这个 data 对象创建 TypeScript 类型,根据 EContentType 正确键入什么?

类似(伪):

type TDataType<ContentType> = {
   [ContentType.IMAGE]: {path: string, type: string}
   [ContentType.VIDEO]: {path: string, length: number}
}

用法:

const concreteType: EContentType = EcontentType.IMAGE;

const typedDataField = dataField as TDataType<concreteType>;

这可能吗?或者不是,因为 TypeScript 只是静态类型的...... 任何不同的想法如何保证类型安全(不允许有人为IMAGE 内容类型保存length 属性)?

如果没有办法做到这一点,那么键入什么会像这样工作:

const data1 = dbDataField as TDataType<EContentType.IMAGE> // {path: string, type: string}
const data2 = dbDataField as TDataType<EContentType.VIDEO> // {path: string, length: number}

【问题讨论】:

    标签: javascript typescript


    【解决方案1】:

    这不起作用,因为您将 ContentType 声明为一种类型但将其用作值。更好的方法是使用接口和extends 泛型上所需的属性,用于您想要预定义的任何内容

    interface TDataType <T>{
       [key: string]: T
    }
    
    let a: TDataType<{path: string, type: string}>;
    a.IMAGE = {path: 'aaa', type: 'bbbb'};
    console.log(a); // output:  "IMAGE": {"path": "aaa", "type": "bbbb"}
    

    或使用Record&lt;Keys, type&gt; 实用程序类型来定义https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeystype

    interface Content{
      path: string, type: string
    }
    
    type ContentType = "IMAGE" | "VIDEO";
    
    const concreteType: Record<ContentType , Content> = {
      IMAGE: { path: "", type: ""}
    };
    

    【讨论】:

      【解决方案2】:
      type TDataType = {
        [key in EContentType]: {path: string, type: string}
      }
      
      type TDataType2<T> = {
        [key in keyof T]: { path: string; type: string };
      };
      

      你可以这样使用。


      示例)

      enum EContentEnum {
        NOTHING,
        IMAGE,
        VIDEO,
      }
      
      type TDataType2<T> = {
        [key in keyof T]: { path: string; type: string };
      };
      
      const contentData: Pick<TDataType2<typeof EContentEnum>, 'IMAGE'> = {
        IMAGE: {
          path: 'imagePath',
          type: 'imageType',
        },
      };
      
      contentData.IMAGE
      

      这是我的答案,但我不确定你是否想要。

      【讨论】:

      • 这似乎行不通......我需要有通用的动态,而不是静态写入代码。我在问题中添加了Usage: 示例。
      • 对不起,没有帮助...我认为 typescript 不支持动态类型。只支持静态类型。
      • 我知道,这就是我问的原因:/ 那么基于静态泛型的类型呢?像这样:TDataType&lt;EContentType.IMAGE&gt;
      • 我不推荐TDataType&lt;EContentType.IMAGE&gt;,因为TDataType2&lt;EContentEnum&gt;是包含你想要的类型。
      • 好的,但是你如何在一种类型中定义多个对象呢?我在你的例子中没有看到它
      猜你喜欢
      • 2019-12-28
      • 2019-07-23
      • 2020-03-22
      • 2019-05-30
      • 1970-01-01
      • 2023-03-30
      • 2021-11-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多