Home > other >  Use name of type in other types on TS
Use name of type in other types on TS

Time:09-29

I have types:

type TUser= {
   id: number,
   name: string,
}

type TFields = {
   value: number,
   name: string,
   otherField: string,
}

type TTask = {
   id: number,
   title: string,
}

type TDataMethod = {
   "TField": "fields",
   "TTask": "tasks",
}

base on this types, how i can create type something like that (the part of the Type below is pseudocode):

type TResponse<T> = {
   data: T extends TUser ? TUser[] : {[TDataMethod[T]]: T}
   time: string,
}

for objects

const userResponse: TResponse<TUser> = {
   data: [
      id: 1,
      name: "John",
   ],
   time: "13 august 2022"
}

const taskResponse: TResponse<TTask> = {
   data: {
      tasks: {
         id: 1,
         title: "Some task",
      }
   },
   time: "14 august 2022"
}

or i have one way - use extends declaration?

CodePudding user response:

It is possible with some Typescript "programming".

For example, I have these interfaces.

interface User {
  name: string;
  age: number;
}

interface Bot {
  name: string;
  author: string;
}

The Metadata should be an array so we could iterate from it.

type Metadata = [
  {
    name: 'users';  // here's the property
    type: User;     // here's the type
  },
  {
    name: 'bots';
    type: Bot;
  }
];

We don't actually could iterate from it. So, create an helper named ArrayUnshift which will unshift (remove first item) from the generic type. If the generic type (Array) is [first, ...rest], then return the rest so the first item is removed.

type ArrayUnshift<Array extends any[]> = 
  Array extends [infer First, ...infer Rest] ?
    Rest : never;

Then we could itearate the Metadata. If the first Metadata.type is equal to generic type, then return the Metadata.name, if not recursive to itself but unshift the Metadata.

type MetadataProperty<T extends any, Data extends any[] = Metadata> =
  Data[0]['type'] extends T ?
    Data[0]['name'] : MetadataProperty<T, ArrayUnshift<Data>>;

Last, create ResponseData with MetadataProperty<T> as its property.

interface ResponseData<T extends object> {
  time: string;
  data: MetadataProperty<T> extends string ? {
    [Key in MetadataProperty<T>]: T;
  } : {
    string: T;  // fallback to avoid error
  }
}

There's a repo that related to this topic, take a look to Type Challenges.


EDIT: Or you could simply use Extract utility as being said by @caTS.

You don't need to "iterate" over them; just get the elements as a union and use Extract: Extract<Metadata[number], { type: T }>["name"].

  • Related