mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
SDK Support for literal field types (#19792)
Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch>
This commit is contained in:
5
.changeset/funny-hornets-compete.md
Normal file
5
.changeset/funny-hornets-compete.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@directus/sdk": minor
|
||||
---
|
||||
|
||||
Added support for literal field types in the SDK
|
||||
@@ -9,7 +9,7 @@ export type DirectusActivity<Schema extends object> = MergeCoreCollection<
|
||||
id: number;
|
||||
action: string;
|
||||
user: DirectusUser<Schema> | string | null;
|
||||
timestamp: string;
|
||||
timestamp: 'datetime';
|
||||
ip: string | null;
|
||||
user_agent: string | null;
|
||||
collection: string;
|
||||
|
||||
@@ -9,7 +9,7 @@ export type DirectusDashboard<Schema extends object> = MergeCoreCollection<
|
||||
name: string;
|
||||
icon: string;
|
||||
note: string | null;
|
||||
date_created: string | null;
|
||||
date_created: 'datetime' | null;
|
||||
user_created: DirectusUser<Schema> | string | null;
|
||||
color: string | null;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ export type DirectusFile<Schema extends object> = MergeCoreCollection<
|
||||
type: string | null;
|
||||
folder: DirectusFolder<Schema> | string | null;
|
||||
uploaded_by: DirectusUser<Schema> | string | null;
|
||||
uploaded_on: string;
|
||||
uploaded_on: 'datetime';
|
||||
modified_by: DirectusUser<Schema> | string | null;
|
||||
modified_on: string;
|
||||
modified_on: 'datetime';
|
||||
charset: string | null;
|
||||
filesize: string | null;
|
||||
width: number | null;
|
||||
|
||||
@@ -16,7 +16,7 @@ export type DirectusFlow<Schema extends object> = MergeCoreCollection<
|
||||
accountability: string | null;
|
||||
options: Record<string, any> | null;
|
||||
operation: DirectusOperation<Schema> | string | null;
|
||||
date_created: string | null;
|
||||
date_created: 'datetime' | null;
|
||||
user_created: DirectusUser<Schema> | string | null;
|
||||
}
|
||||
>;
|
||||
|
||||
@@ -6,7 +6,7 @@ export type DirectusNotification<Schema extends object> = MergeCoreCollection<
|
||||
'directus_notifications',
|
||||
{
|
||||
id: string;
|
||||
timestamp: string | null;
|
||||
timestamp: 'datetime' | null;
|
||||
status: string | null;
|
||||
recipient: DirectusUser<Schema> | string;
|
||||
sender: DirectusUser<Schema> | string | null;
|
||||
|
||||
@@ -17,7 +17,7 @@ export type DirectusOperation<Schema extends object> = MergeCoreCollection<
|
||||
resolve: DirectusOperation<Schema> | string | null;
|
||||
reject: DirectusOperation<Schema> | string | null;
|
||||
flow: DirectusFlow<Schema> | string;
|
||||
date_created: string | null;
|
||||
date_created: 'datetime' | null;
|
||||
user_created: DirectusUser<Schema> | string | null;
|
||||
}
|
||||
>;
|
||||
|
||||
@@ -19,7 +19,7 @@ export type DirectusPanel<Schema extends object> = MergeCoreCollection<
|
||||
width: number;
|
||||
height: number;
|
||||
options: Record<string, any> | null;
|
||||
date_created: string | null;
|
||||
date_created: 'datetime' | null;
|
||||
user_created: DirectusUser<Schema> | string | null;
|
||||
}
|
||||
>;
|
||||
|
||||
@@ -30,7 +30,7 @@ export type DirectusSettings<Schema extends object> = MergeCoreCollection<
|
||||
storage_default_folder: DirectusFolder<Schema> | string | null;
|
||||
basemaps: Record<string, any> | null;
|
||||
mapbox_key: string | null;
|
||||
module_bar: any | null;
|
||||
module_bar: 'json' | null;
|
||||
project_descriptor: string | null;
|
||||
default_language: string;
|
||||
custom_aspect_ratios: Record<string, any> | null;
|
||||
|
||||
@@ -13,9 +13,9 @@ export type DirectusShare<Schema extends object> = MergeCoreCollection<
|
||||
role: DirectusRole<Schema> | string | null;
|
||||
password: string | null;
|
||||
user_created: DirectusUser<Schema> | string | null;
|
||||
date_created: string | null;
|
||||
date_start: string | null;
|
||||
date_end: string | null;
|
||||
date_created: 'datetime' | null;
|
||||
date_start: 'datetime' | null;
|
||||
date_end: 'datetime' | null;
|
||||
times_used: number | null;
|
||||
max_uses: number | null;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { MergeCoreCollection } from '../index.js';
|
||||
import type { DirectusRole, MergeCoreCollection } from '../index.js';
|
||||
import type { DirectusFile } from './file.js';
|
||||
|
||||
/**
|
||||
@@ -22,9 +22,9 @@ export type DirectusUser<Schema extends object> = MergeCoreCollection<
|
||||
theme: string | null;
|
||||
tfa_secret: string | null;
|
||||
status: string;
|
||||
role: string | null;
|
||||
role: DirectusRole<Schema> | string | null;
|
||||
token: string | null;
|
||||
last_access: string | null;
|
||||
last_access: 'datetime' | null;
|
||||
last_page: string | null;
|
||||
provider: string;
|
||||
external_identifier: string | null;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { AllCollections, GetCollection, ItemType, Query, RelationalFields, UnpackList } from './index.js';
|
||||
import type { ArrayFunctions, DateTimeFunctions, MappedFieldNames, MappedFunctionFields } from './functions.js';
|
||||
import type { AllCollections, GetCollection, LiteralFields, Query, RelationalFields, UnpackList } from './index.js';
|
||||
|
||||
export type GroupingFunctions = {
|
||||
date: 'year' | 'month' | 'week' | 'day' | 'weekday' | 'hour' | 'minute' | 'second';
|
||||
@@ -52,8 +53,8 @@ export type AggregateRecord<Fields = string> = {
|
||||
* GroupBy parameters
|
||||
*/
|
||||
export type GroupByFields<Schema extends object, Item> =
|
||||
| WrappedFields<DateFields<Schema, Item>, GroupingFunctions['date']>
|
||||
| WrappedFields<RelationalFields<Schema, Item>, GroupingFunctions['array']>;
|
||||
| WrappedFields<LiteralFields<Item, 'datetime'>, DateTimeFunctions>
|
||||
| WrappedFields<RelationalFields<Schema, Item>, ArrayFunctions>;
|
||||
|
||||
/**
|
||||
* Aggregation input options
|
||||
@@ -78,16 +79,18 @@ export type AggregationOutput<
|
||||
Options extends AggregationOptions<Schema, Collection>
|
||||
> = ((Options['groupBy'] extends string[]
|
||||
? UnpackList<GetCollection<Schema, Collection>> extends infer Item
|
||||
? MappedFunctionFields<Schema, Item> extends infer FieldMap
|
||||
? MappedFieldNames<Schema, Item> extends infer NamesMap
|
||||
? {
|
||||
[Field in UnpackList<Options['groupBy']> as TranslateFunctionField<FieldMap, Field>]: ExtractFieldName<
|
||||
NamesMap,
|
||||
Field
|
||||
> extends keyof Item
|
||||
? Item[ExtractFieldName<NamesMap, Field>]
|
||||
: never;
|
||||
}
|
||||
? Item extends object
|
||||
? MappedFunctionFields<Schema, Item> extends infer FieldMap
|
||||
? MappedFieldNames<Schema, Item> extends infer NamesMap
|
||||
? {
|
||||
[Field in UnpackList<Options['groupBy']> as TranslateFunctionField<
|
||||
FieldMap,
|
||||
Field
|
||||
>]: TranslateFunctionField<NamesMap, Field> extends keyof Item
|
||||
? Item[TranslateFunctionField<NamesMap, Field>]
|
||||
: never;
|
||||
}
|
||||
: never
|
||||
: never
|
||||
: never
|
||||
: never
|
||||
@@ -111,43 +114,8 @@ type WrappedFields<Fields, Funcs> = Fields extends string
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Try to detect date fields
|
||||
* TODO all we can really check is for string types, can we do more?
|
||||
* Translate function names based on provided map
|
||||
*/
|
||||
type DateFields<Schema extends object, Item> = {
|
||||
[Key in keyof Item]: Extract<Item[Key], ItemType<Schema>> extends never
|
||||
? NonNullable<Item[Key]> extends string
|
||||
? Key
|
||||
: never
|
||||
: never;
|
||||
}[keyof Item];
|
||||
|
||||
/**
|
||||
* The types below are helpers for working with fields wrapped in functions
|
||||
*
|
||||
* TODO this must be doable in a simpler way to handle the logic below!
|
||||
*/
|
||||
type PermuteFields<Fields, Funcs> = Fields extends string ? (Funcs extends string ? [Fields, Funcs] : never) : never;
|
||||
|
||||
type MapFunctionFields<Fields, Funcs> = {
|
||||
[F in PermuteFields<Fields, Funcs> as `${F[1]}(${F[0]})`]: `${F[0]}_${F[1]}`;
|
||||
};
|
||||
type MapFieldNames<Fields, Funcs> = {
|
||||
[F in PermuteFields<Fields, Funcs> as `${F[1]}(${F[0]})`]: F[0];
|
||||
};
|
||||
|
||||
type MappedFunctionFields<Schema extends object, Item> = MapFunctionFields<
|
||||
DateFields<Schema, Item>,
|
||||
GroupingFunctions['date']
|
||||
> &
|
||||
MapFunctionFields<RelationalFields<Schema, Item>, GroupingFunctions['array']>;
|
||||
|
||||
type MappedFieldNames<Schema extends object, Item> = MapFieldNames<
|
||||
DateFields<Schema, Item>,
|
||||
GroupingFunctions['date']
|
||||
> &
|
||||
MapFieldNames<RelationalFields<Schema, Item>, GroupingFunctions['array']>;
|
||||
|
||||
type TranslateFunctionField<FieldMap, Field> = Field extends keyof FieldMap
|
||||
? FieldMap[Field] extends string
|
||||
? FieldMap[Field]
|
||||
@@ -155,11 +123,3 @@ type TranslateFunctionField<FieldMap, Field> = Field extends keyof FieldMap
|
||||
: Field extends string
|
||||
? Field
|
||||
: never;
|
||||
|
||||
type ExtractFieldName<FieldMap, Field> = Field extends keyof FieldMap
|
||||
? FieldMap[Field] extends string
|
||||
? FieldMap[Field]
|
||||
: never
|
||||
: Field extends string
|
||||
? Field
|
||||
: never;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { FunctionFields } from './functions.js';
|
||||
import type { ExtractItem } from './query.js';
|
||||
import type { ItemType, RelationalFields, RemoveRelationships } from './schema.js';
|
||||
import type { UnpackList } from './utils.js';
|
||||
@@ -6,6 +7,7 @@ import type { UnpackList } from './utils.js';
|
||||
* Fields querying, including nested relational fields
|
||||
*/
|
||||
export type QueryFields<Schema extends object, Item> = WrapQueryFields<
|
||||
Schema,
|
||||
Item,
|
||||
QueryFieldsRelational<Schema, UnpackList<Item>>
|
||||
>;
|
||||
@@ -13,7 +15,12 @@ export type QueryFields<Schema extends object, Item> = WrapQueryFields<
|
||||
/**
|
||||
* Wrap array of fields
|
||||
*/
|
||||
export type WrapQueryFields<Item, NestedFields> = readonly ('*' | keyof UnpackList<Item> | NestedFields)[];
|
||||
export type WrapQueryFields<Schema extends object, Item, NestedFields> = readonly (
|
||||
| '*'
|
||||
| keyof UnpackList<Item>
|
||||
| NestedFields
|
||||
| FunctionFields<Schema, UnpackList<Item>>
|
||||
)[];
|
||||
|
||||
/**
|
||||
* Object of nested relational fields in a given Item with it's own fields available for selection
|
||||
@@ -36,6 +43,7 @@ export type ManyToAnyFields<Schema extends object, Item> = ExtractItem<Schema, I
|
||||
? 'collection' extends keyof TItem
|
||||
? 'item' extends keyof TItem
|
||||
? WrapQueryFields<
|
||||
Schema,
|
||||
TItem,
|
||||
Omit<QueryFieldsRelational<Schema, UnpackList<Item>>, 'item'> & {
|
||||
item?: {
|
||||
@@ -76,7 +84,9 @@ export type HasNestedFields<Fields> = UnpackList<Fields> extends infer Field
|
||||
/**
|
||||
* Return all keys if Fields is undefined or contains '*'
|
||||
*/
|
||||
export type FieldsWildcard<Item extends object, Fields> = UnpackList<Fields> extends infer Field
|
||||
export type FieldsWildcard<Item extends object, Fields> = unknown extends Fields
|
||||
? keyof Item
|
||||
: UnpackList<Fields> extends infer Field
|
||||
? Field extends undefined
|
||||
? keyof Item
|
||||
: Field extends '*'
|
||||
@@ -107,3 +117,10 @@ type AllKeys<T> = T extends any ? keyof T : never;
|
||||
export type PickFlatFields<Schema extends object, Item, Fields> = Extract<Fields, keyof Item> extends never
|
||||
? never
|
||||
: Pick<RemoveRelationships<Schema, Item>, Extract<Fields, keyof Item>>;
|
||||
|
||||
/**
|
||||
* Extract a specific literal type from a collection
|
||||
*/
|
||||
export type LiteralFields<Item, Type extends string> = {
|
||||
[Key in keyof Item]: Extract<Item[Key], Type>[] extends never[] ? never : Key;
|
||||
}[keyof Item];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { MappedFieldNames } from './functions.js';
|
||||
import type { RelationalFields } from './schema.js';
|
||||
import type { UnpackList } from './utils.js';
|
||||
import type { Merge, UnpackList } from './utils.js';
|
||||
|
||||
/**
|
||||
* Filters
|
||||
@@ -10,13 +11,28 @@ export type QueryFilter<Schema extends object, Item> = WrapLogicalFilters<Nested
|
||||
* Query filters without logical filters
|
||||
*/
|
||||
export type NestedQueryFilter<Schema extends object, Item> = UnpackList<Item> extends infer FlatItem
|
||||
? {
|
||||
[Field in keyof FlatItem]?:
|
||||
| (Field extends RelationalFields<Schema, FlatItem>
|
||||
? WrapRelationalFilters<NestedQueryFilter<Schema, FlatItem[Field]>>
|
||||
: never)
|
||||
| FilterOperators<FlatItem[Field]>;
|
||||
}
|
||||
? Merge<
|
||||
{
|
||||
[Field in keyof FlatItem]?:
|
||||
| (Field extends RelationalFields<Schema, FlatItem>
|
||||
? WrapRelationalFilters<NestedQueryFilter<Schema, FlatItem[Field]>>
|
||||
: never)
|
||||
| FilterOperators<FlatItem[Field]>;
|
||||
},
|
||||
MappedFieldNames<Schema, Item> extends infer Funcs
|
||||
? {
|
||||
[Func in keyof Funcs]?: Funcs[Func] extends infer Field
|
||||
? Field extends keyof FlatItem
|
||||
?
|
||||
| (Field extends RelationalFields<Schema, FlatItem>
|
||||
? WrapRelationalFilters<NestedQueryFilter<Schema, FlatItem[Field]>>
|
||||
: never)
|
||||
| FilterOperators<FlatItem[Field]>
|
||||
: never
|
||||
: never;
|
||||
}
|
||||
: never
|
||||
>
|
||||
: never;
|
||||
|
||||
/**
|
||||
@@ -72,8 +88,9 @@ export type WrapRelationalFilters<Filters> =
|
||||
*/
|
||||
export type LogicalFilterOperators = '_or' | '_and';
|
||||
|
||||
export type WrapLogicalFilters<Filters> =
|
||||
| {
|
||||
[Operator in LogicalFilterOperators]?: WrapLogicalFilters<Filters>[];
|
||||
}
|
||||
| Filters;
|
||||
export type WrapLogicalFilters<Filters extends object> = Merge<
|
||||
{
|
||||
[Operator in LogicalFilterOperators]?: WrapLogicalFilters<Filters>[];
|
||||
},
|
||||
Filters
|
||||
>;
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import type { LiteralFields } from './fields.js';
|
||||
import type { ItemType, RelationalFields } from './schema.js';
|
||||
import type { Merge } from './utils.js';
|
||||
|
||||
/**
|
||||
* Available query functions
|
||||
*/
|
||||
export type DateTimeFunctions = 'year' | 'month' | 'week' | 'day' | 'weekday' | 'hour' | 'minute' | 'second';
|
||||
export type ArrayFunctions = 'count';
|
||||
|
||||
export type QueryFunctions = {
|
||||
date: 'year' | 'month' | 'week' | 'day' | 'weekday' | 'hour' | 'minute' | 'second';
|
||||
array: 'count';
|
||||
datetime: DateTimeFunctions;
|
||||
json: ArrayFunctions;
|
||||
csv: ArrayFunctions;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -14,3 +22,59 @@ export type PermuteFields<Fields, Funcs> = Fields extends string
|
||||
? [Fields, Funcs]
|
||||
: never
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Get all many relations on an item
|
||||
*/
|
||||
type RelationalFunctions<Schema extends object, Item> = keyof {
|
||||
[Key in RelationalFields<Schema, Item> as Extract<Item[Key], ItemType<Schema>> extends any[] ? Key : never]: Key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a map of function fields and their resulting output names
|
||||
*/
|
||||
type TranslateFunctionFields<Fields, Funcs> = {
|
||||
[F in PermuteFields<Fields, Funcs> as `${F[1]}(${F[0]})`]: `${F[0]}_${F[1]}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Combine the various function types
|
||||
*/
|
||||
export type FunctionFields<Schema extends object, Item> =
|
||||
| {
|
||||
[Type in keyof QueryFunctions]: TypeFunctionFields<Item, Type>;
|
||||
}[keyof QueryFunctions]
|
||||
| keyof TranslateFunctionFields<RelationalFunctions<Schema, Item>, ArrayFunctions>;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export type TypeFunctionFields<Item, Type extends keyof QueryFunctions> = keyof TranslateFunctionFields<
|
||||
LiteralFields<Item, Type>,
|
||||
QueryFunctions[Type]
|
||||
>;
|
||||
|
||||
/**
|
||||
* Map all possible function fields on an item
|
||||
*/
|
||||
export type MappedFunctionFields<Schema extends object, Item> = Merge<
|
||||
TranslateFunctionFields<RelationalFunctions<Schema, Item>, ArrayFunctions>,
|
||||
TranslateFunctionFields<LiteralFields<Item, 'datetime'>, DateTimeFunctions> &
|
||||
TranslateFunctionFields<LiteralFields<Item, 'json' | 'csv'>, ArrayFunctions>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Create a map of function fields with its original field name
|
||||
*/
|
||||
type FunctionFieldNames<Fields, Funcs> = {
|
||||
[F in PermuteFields<Fields, Funcs> as `${F[1]}(${F[0]})`]: F[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Map all possible function fields to name on an item
|
||||
*/
|
||||
export type MappedFieldNames<Schema extends object, Item> = Merge<
|
||||
FunctionFieldNames<RelationalFunctions<Schema, Item>, ArrayFunctions>,
|
||||
FunctionFieldNames<LiteralFields<Item, 'datetime'>, DateTimeFunctions> &
|
||||
FunctionFieldNames<LiteralFields<Item, 'json' | 'csv'>, ArrayFunctions>
|
||||
>;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { FieldsWildcard, HasManyToAnyRelation, PickFlatFields, PickRelationalFields } from './fields.js';
|
||||
import type { FieldsWildcard, HasManyToAnyRelation, PickRelationalFields } from './fields.js';
|
||||
import type { MappedFunctionFields } from './functions.js';
|
||||
import type { ItemType } from './schema.js';
|
||||
import type { IfAny, IsNullable, Merge, Mutable, UnpackList } from './utils.js';
|
||||
|
||||
@@ -14,13 +15,15 @@ export type ApplyQueryFields<
|
||||
CollectionItem extends object = UnpackList<Collection>,
|
||||
Fields = UnpackList<Mutable<ReadonlyFields>>,
|
||||
RelationalFields = PickRelationalFields<Fields>,
|
||||
RelationalKeys = RelationalFields extends never ? never : keyof RelationalFields,
|
||||
FlatFields = FieldsWildcard<CollectionItem, Exclude<Fields, RelationalKeys>>
|
||||
RelationalKeys extends keyof RelationalFields = RelationalFields extends never ? never : keyof RelationalFields,
|
||||
FlatFields extends keyof CollectionItem = FieldsWildcard<CollectionItem, Exclude<Fields, RelationalKeys>>
|
||||
> = IfAny<
|
||||
Schema,
|
||||
Record<string, any>,
|
||||
Merge<
|
||||
PickFlatFields<Schema, CollectionItem, FlatFields>,
|
||||
MappedFunctionFields<Schema, CollectionItem> extends infer FF
|
||||
? MapFlatFields<CollectionItem, FlatFields, FF extends Record<string, string> ? FF : Record<string, string>>
|
||||
: never,
|
||||
RelationalFields extends never
|
||||
? never
|
||||
: {
|
||||
@@ -77,3 +80,38 @@ export type ApplyNestedQueryFields<Schema extends object, Collection, Fields> =
|
||||
* Carry nullability of
|
||||
*/
|
||||
export type RelationNullable<Relation, Output> = IsNullable<Relation, Output | null, Output>;
|
||||
|
||||
/**
|
||||
* Map literal types to actual output types
|
||||
*/
|
||||
export type MapFlatFields<
|
||||
Item extends object,
|
||||
Fields extends keyof Item,
|
||||
FunctionMap extends Record<string, string>
|
||||
> = {
|
||||
[F in Fields as F extends keyof FunctionMap ? FunctionMap[F] : F]: F extends keyof FunctionMap
|
||||
? FunctionOutputType
|
||||
: Extract<Item[F], keyof FieldOutputMap> extends infer A
|
||||
? A[] extends never[]
|
||||
? Item[F]
|
||||
: A extends keyof FieldOutputMap
|
||||
? FieldOutputMap[A] | Exclude<Item[F], A>
|
||||
: Item[F]
|
||||
: Item[F];
|
||||
};
|
||||
|
||||
// Possible JSON types
|
||||
type JsonPrimitive = null | boolean | number | string;
|
||||
type JsonValue = JsonPrimitive | JsonPrimitive[] | { [key: string]: JsonValue };
|
||||
|
||||
/**
|
||||
* Output map for specific literal types
|
||||
*/
|
||||
export type FieldOutputMap = {
|
||||
json: JsonValue;
|
||||
csv: string[];
|
||||
datetime: string;
|
||||
};
|
||||
|
||||
// all functions return a numeric type
|
||||
type FunctionOutputType = number;
|
||||
|
||||
@@ -24,7 +24,8 @@ export type Merge<A, B, TypeA = NeverToUnknown<A>, TypeB = NeverToUnknown<B>> =
|
||||
/**
|
||||
* Fallback never to unknown
|
||||
*/
|
||||
export type NeverToUnknown<T> = [T] extends [never] ? unknown : T;
|
||||
export type NeverToUnknown<T> = IfNever<T, unknown>;
|
||||
export type IfNever<T, Y> = [T] extends [never] ? Y : T;
|
||||
|
||||
/**
|
||||
* Test for any
|
||||
@@ -37,3 +38,8 @@ export type IsNullable<T, Y = true, N = never> = T | null extends T ? Y : N;
|
||||
export type NestedPartial<Item extends object> = {
|
||||
[Key in keyof Item]?: Item[Key] extends object ? NestedPartial<Item[Key]> : Item[Key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve type to its final object
|
||||
*/
|
||||
export type Identity<U> = U extends infer A ? A : U;
|
||||
|
||||
Reference in New Issue
Block a user