基于泛型类型定义TypeScript类型



让我们在TypeScript(4.0.5(:中创建一个SQL数据库表,其中列data为JSON类型

enum EContentType {
NOTHING,
IMAGE,
VIDEO
}

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

示例:

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

是否可以使用基于EContentType正确键入的泛型为该data对象创建TypeScript类型?

类似(伪(:

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}

这将不起作用,因为您将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<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 };
};

你可以这样使用。


示例(

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

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

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

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>;

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

最新更新