import type { Attribute, Common, Utils } from '@strapi/types'; type IDProperty = { id: number }; type InvalidKeys = Utils.Object.KeysBy< Attribute.GetAll, Attribute.Private | Attribute.Password >; export type GetValues = { [TKey in Attribute.GetOptionalKeys]?: Attribute.Get< TSchemaUID, TKey > extends infer TAttribute extends Attribute.Attribute ? GetValue : never; } & { [TKey in Attribute.GetRequiredKeys]-?: Attribute.Get< TSchemaUID, TKey > extends infer TAttribute extends Attribute.Attribute ? GetValue : never; } extends infer TValues ? // Remove invalid keys (private, password) Omit> : never; type RelationValue = TAttribute extends Attribute.Relation< infer _TOrigin, infer TRelationKind, infer TTarget > ? Utils.Expression.MatchFirst< [ [ Utils.Expression.Extends, TRelationKind extends `${string}ToMany` ? Omit, 'meta'> : APIResponse, ], ], `TODO: handle other relation kind (${TRelationKind})` > : never; type ComponentValue = TAttribute extends Attribute.Component ? Utils.Expression.If< TRepeatable, (IDProperty & GetValues)[], (IDProperty & GetValues) > : never; type DynamicZoneValue = TAttribute extends Attribute.DynamicZone ? Array< Utils.Array.Values extends infer TComponentUID ? TComponentUID extends Common.UID.Component ? { __component: TComponentUID } & IDProperty & GetValues : never : never > : never; type MediaValue = TAttribute extends Attribute.Media< infer _TKind, infer TMultiple > ? Utils.Expression.If< TMultiple, APIResponseData<'plugin::upload.file'>[], APIResponseData<'plugin::upload.file'> > : never; export type GetValue = Utils.Expression.If< Utils.Expression.IsNotNever, Utils.Expression.MatchFirst< [ // Relation [ Utils.Expression.Extends>, RelationValue, ], // DynamicZone [ Utils.Expression.Extends>, DynamicZoneValue, ], // Component [ Utils.Expression.Extends>, ComponentValue, ], // Media [Utils.Expression.Extends>, MediaValue], // Fallback // If none of the above attribute type, fallback to the original Attribute.GetValue (while making sure it's an attribute) [Utils.Expression.True, Attribute.GetValue], ], unknown >, unknown >; interface APIResponseData extends IDProperty { attributes: GetValues; } export interface APIResponseCollectionMetadata { page: number; pageSize: number; pageCount: number; total: number; } export interface APIResponse { data: APIResponseData; } export interface APIResponseCollection { data: APIResponseData[]; meta: APIResponseCollectionMetadata; } // TEST declare function fetchOne(uid: T): Promise>; declare function fetchMany( uid: T ): Promise>; fetchOne('api::restaurant.restaurant').then((res) => { const { /* ... */ } = res.data.attributes; console.log(/* ... */); }); fetchMany('api::restaurant.restaurant').then((res) => { res.data.forEach((entity) => { const { /* ... */ } = entity.attributes; console.log(/* ... */); }); });