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