简体   繁体   中英

Use name of type in other types on TS

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?

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"] .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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