@jeroenhuinink/tsmapper
Version:
JSON to Typescript object mapper
188 lines (187 loc) • 4.75 kB
TypeScript
/**
* The source for the mapper is assumed to be JSON response from an API that is indexed with strings. Every value is unknown.
*/
export interface Source {
[key: string]: unknown;
}
declare type ValueFieldType = string | number | boolean | Date;
interface BaseOptions {
/**
* Target type
*/
type?: string;
/**
* The key to the value.
*/
key?: string;
optional?: boolean;
default?: unknown;
}
export interface ValueOptions extends BaseOptions {
/**
* Target type
*/
type?: 'string' | 'boolean' | 'number' | 'date' | 'isodate' | undefined;
/**
* Function to apply to the value before it is returned
*/
map?: (value: unknown, source: Source) => unknown;
/**
* Default value for the entry
*/
default?: ValueFieldType;
}
interface ObjectOptions<T = {}> {
/**
* Target type 'object'
*/
type?: 'object';
/**
* The child mapper
*/
mapper: Mapper<T>;
/**
* Default value for the entry
*/
default?: T;
}
export interface ArrayOptions<T = {}> {
/**
* Target type 'array'
*/
type?: 'array';
/**
* The type for the array items
* */
itemType: ObjectOptions<T> | EnumArrayOptions<T>;
/**
* Default value for the entry
*/
default?: T[];
}
export interface EnumArrayOptions<T = {}> {
/**
* Target type 'array'
*/
type: 'enum';
/**
* The type for the array items
* */
map: (s: any) => T;
/**
* Default value for the entry
*/
default?: T[];
}
export interface EnumOptions<T = {}> {
type?: 'enum';
/**
* Target type 'enum'
*/
enum: readonly T[];
}
export declare type Options = BaseOptions & (ValueOptions | ObjectOptions | ArrayOptions | EnumArrayOptions | EnumOptions);
export declare type MapperField = Options & {
key: string;
name: string;
};
declare type ArrayElement<T> = T extends readonly (infer R)[] ? R : never;
declare type InferredFieldType<O extends Options> = O extends never ? never : O extends {
type: 'string';
optional: true;
} ? string | undefined : O extends {
type: 'string';
} ? string : O extends {
type: 'number';
optional: true;
} ? number | undefined : O extends {
type: 'number';
} ? number : O extends {
type: 'boolean';
optional: true;
} ? boolean | undefined : O extends {
type: 'boolean';
} ? boolean : O extends {
type: 'date';
optional: true;
} ? Date | undefined : O extends {
type: 'date';
} ? Date : O extends {
type: 'isodate';
optional: true;
} ? string | undefined : O extends {
type: 'isodate';
} ? string : O extends {
type: 'array';
itemType: {
type: 'enum';
map: (s: unknown) => infer T;
};
optional: true;
} ? T[] | undefined : O extends {
type: 'array';
itemType: {
type: 'enum';
map: (s: unknown) => infer T;
};
} ? T[] : O extends {
enum: infer T;
optional: true;
} ? ArrayElement<T> | undefined : O extends {
enum: infer T;
} ? ArrayElement<T> : O extends {
mapper: Mapper<infer T>;
optional: true;
} ? T | undefined : O extends {
mapper: Mapper<infer T>;
} ? T : O extends {
itemType: {
type: 'string';
};
} ? string[] : O extends {
itemType: {
type: 'number';
};
} ? number[] : O extends {
itemType: {
mapper: Mapper<infer T>;
};
optional: true;
} ? T[] | undefined : O extends {
itemType: {
mapper: Mapper<infer T>;
};
} ? T[] : O extends {
default: infer T;
} ? T : unknown;
/**
* Type for the set of functions that are used to map values from the source to the target.
*/
export declare type MapFunctions = {
string: (val: unknown) => string;
number: (val: unknown) => number;
boolean: (val: unknown) => boolean;
date: (val: unknown) => Date;
isodate: (val: unknown) => string;
symbol: (val: unknown) => symbol;
undefined: (val: unknown) => string;
object: (val: unknown) => string;
function: (val: unknown) => unknown;
};
export interface ImplicitMapper<T = {}> {
field<K extends keyof T, O extends Options>(key: K, options: O): ImplicitMapper<Omit<T, K> & {
[key in K]: InferredFieldType<O>;
}>;
field<K extends string, O extends Options>(key: K, options: O): ImplicitMapper<T & {
[key in K]: InferredFieldType<O>;
}>;
map(source: Source): {
[key in keyof T]: T[key];
};
}
export interface ExplicitMapper<T> {
field<K extends keyof T, O extends Options>(key: K, options: O): ExplicitMapper<T>;
map(source: Source): T;
}
export declare type Mapper<T> = ImplicitMapper<T> | ExplicitMapper<T>;
export {};