Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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):

enum EContentType {
  NOTHING,
  IMAGE,
  VIDEO
}

Depending on ContentType I am saving different JSON schema into data column into my database.

Example:

  • For IMAGE, saving {"path": "/foo/bar", "type": "jpeg"}
  • For VIDEO, saving {"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?

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)?

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}
like image 344
Baterka Avatar asked Aug 10 '26 10:08

Baterka


1 Answers

This wouldn't work as you're declaring ContentType as a type but using it as a value. A better approach would be to use an interface and extends your desired properties on generic for anything you would want predefined

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

interface Content{
  path: string, type: string
}

type ContentType = "IMAGE" | "VIDEO";

const concreteType: Record<ContentType , Content> = {
  IMAGE: { path: "", type: ""}
};
like image 178
Rogelio Avatar answered Aug 13 '26 00:08

Rogelio