基于泛型类型定义TypeScript类型

1zmg4dgp  于 2023-08-08  发布在  TypeScript
关注(0)|答案(3)|浏览(141)

让我们有一个SQL数据库表,列data是JSON类型,下面的枚举是TypeScript(4.0.5):

enum EContentType {
  NOTHING,
  IMAGE,
  VIDEO
}

字符串
根据ContentType,我将不同的JSON模式保存到数据库的data列中。
范例:

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

是否可以使用泛型为data对象创建TypeScript类型,基于EContentType将正确键入什么?
类似于(pseudo):

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}

h6my8fg2

h6my8fg21#

如果你把ContentType声明为一个类型,而把它作为一个值,那么这是行不通的。更好的方法是在generic上使用接口和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<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: ""}
};

v2g6jxz6

v2g6jxz62#

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


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

6xfqseft

6xfqseft3#

有点晚了,但这里有一个可能的解决方案:

enum EContentType {
    NOTHING,
    IMAGE,
    VIDEO,
}
type TBaseDataType = {
    path: string;
};
interface IImageType extends TBaseDataType{
    type: string;
}
interface IVideoType extends TBaseDataType {
    length: number;
}
type TDataType<T extends EContentType = EContentType.IMAGE> = T extends EContentType.IMAGE ? IImageType : IVideoType;

const image: TDataType<EContentType.IMAGE>;

字符串
这只是一个示例,但它允许您使用相同的类型并动态选择所需的图像或视频类型。

相关问题