简体   繁体   English

基于泛型类型定义 TypeScript 类型

[英]Define TypeScript type based on generic type

Let's have SQL database table with column data of type JSON and this enum in TypeScript (4.0.5):让我们拥有 SQL 数据库表,其列data类型为 JSON 和 TypeScript (4.0.5) 中的此枚举:

enum EContentType {
  NOTHING,
  IMAGE,
  VIDEO
}

Depending on ContentType I am saving different JSON schema into data column into my database.根据ContentType ,我将不同的 JSON 模式保存到数据库中的data列中。

Example:例子:

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

Is possible to create TypeScript type for this data object with generics what will be correctly typed based on EContentType ?是否可以使用 generics 为该data创建 TypeScript 类型 object 将根据EContentType正确键入什么?

Something like (pseudo):像(伪)这样的东西:

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

Usage:用法:

const concreteType: EContentType = EcontentType.IMAGE;

const typedDataField = dataField as TDataType<concreteType>;

Is this possible?这可能吗? Or it is not, because TypeScript is only statically typed... Any different idea how to guarantee type safety (not allow someone to save length property for IMAGE content type)?或者不是,因为 TypeScript 只是静态类型的......有什么不同的想法如何保证类型安全(不允许有人为IMAGE内容类型保存length属性)?

If there is no way to do it what about type what will work like this:如果没有办法做到这一点,那么键入什么会像这样工作:

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

This wouldn't work as you're declaring ContentType as a type but using it as a value.这不起作用,因为您将ContentType声明为类型但将其用作值。 A better approach would be to use an interface and extends your desired properties on generic for anything you would want predefined更好的方法是使用接口并在泛型上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"}

or use The Record<Keys, type> utility type to define https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeystype或使用Record<Keys, type>实用程序类型来定义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: ""}
};
type TDataType = {
  [key in EContentType]: {path: string, type: string}
}

type TDataType2<T> = {
  [key in keyof T]: { path: string; type: string };
};

You can use like this.你可以这样使用。


example)例子)

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

This is my answer, but I am not sure if you want it.这是我的答案,但我不确定你是否想要它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM