Skip to content

Commit

Permalink
Add documentation to outputFromOutputFields types
Browse files Browse the repository at this point in the history
  • Loading branch information
JiriLojda committed Nov 23, 2022
1 parent cfd70e4 commit 3426507
Showing 1 changed file with 34 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/fields/output/outputFromOutputFields.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
import { OutputField } from './outputField';

/**
* Iterates over the fields and creates a type of expected output object build up from the fields.
* The resulting object is build as an intersection of smaller objects for each field.
*
* - Leverages TCO for better performance
*
* @example
* const outputFields = [
* {
* key: 'a',
* label: 'my label',
* type: 'string',
* },
* // ...more fields
* ] as const satisfies ReadonlyArray<OutputField>; // as const ensures the most specific type is inferred and satisfies ensures the specific inferred type is still a valid array of output fields
*
* type Output = OutputFromOutputFields<typeof outputFields>;
*
* @example
* OutputFromOutputFields<[{ key: 'a__b'; label: ''; type: 'string' }, { key: 'a__c'; label: ''; type: 'number' }]> =>
* { a: { b: string } } & { a: { c: number } } === { a: { b: string; c: number } }
*/
export type OutputFromOutputFields<Fields extends ReadonlyArray<OutputField>, Acc = {}> =
Fields extends readonly []
? Acc
: Fields extends readonly [infer Field extends OutputField, ...infer RestFields extends ReadonlyArray<OutputField>]
? OutputFromOutputFields<RestFields, Acc & CreateObjectFromField<Field>>
: never;

/**
* Create an object from a single {@link OutputField}. The result will be used in an intersection of all fields to build up the resulting object type.
*/
type CreateObjectFromField<Field extends OutputField> =
Field['key'] extends `${infer ObjectParentKey}__${infer ObjectChildKey}`
? ObjectParentKey extends `${infer ArrayParentKey}[]${infer ArrayChildPart}`
Expand All @@ -17,13 +42,22 @@ type CreateObjectFromField<Field extends OutputField> =
: { readonly [key in Field['key']]: FieldType<Field> }


/**
* Map from possible values of property 'type' on {@link OutputField} to their representation in TS.
*/
type FieldTypeToTSType = {
string: string;
datetime: string;
number: number;
boolean: boolean;
};

/**
* Creates a TS type for an {@link OutputField} property based on its 'type', 'required' and 'list' properties.
*
* - The Lookup parameter is not supposed to be used outside (always the default value should be used).
* It is meant to check (using its restriction) that the {@link FieldTypeToTSType} contains a binding for every possible value of property 'type' of the {@link OutputField} type.
*/
type FieldType<Field extends OutputField, Lookup extends Record<OutputField['type'], unknown> = FieldTypeToTSType> =
MakeListIfNeeded<Field, MakeOptionalIfNeeded<Field, FieldTypeToTSType[Field['type']]>>;

Expand Down

0 comments on commit 3426507

Please sign in to comment.