alwz
Version:
Extendable library for typecasting
215 lines • 8.69 kB
TypeScript
/// <reference types="node" />
export type IS<T> = (input?: unknown) => input is T;
export declare function isIS<T>(input?: unknown): input is IS<T>;
export declare function assertIS<T>(input?: unknown): true | never;
export type Fallback<OUTPUT> = (input?: unknown) => OUTPUT | never;
export declare function isFallback<OUTPUT>(input?: unknown): input is Fallback<OUTPUT>;
export declare function assertFallback<OUTPUT>(input?: unknown): true | never;
export type Conversion<INPUT, OUTPUT> = (this: Converter<OUTPUT>, input: INPUT) => OUTPUT;
export declare function isConversion<INPUT, OUTPUT>(input: unknown): input is Conversion<INPUT, OUTPUT>;
export declare function assertConversion<INPUT, OUTPUT>(input: unknown): true | never;
type TypesMap = {
undefined: undefined;
boolean: boolean;
number: number;
bigint: bigint;
string: string;
symbol: symbol;
};
type TypeConversions<OUTPUT> = {
[Name in keyof TypesMap]: Conversion<TypesMap[Name], OUTPUT>;
};
type TypeConversion<Name, OUTPUT> = Name extends keyof TypeConversions<OUTPUT> ? TypeConversions<OUTPUT>[Name] : never;
/**
* @description converts input data to specific type
* - at first checks if conversion is necessary
* - attempts conversion based on the input data type
* - searches for suitable conversions among registered
* - calls a fallback function
*
* @example <caption>converter creation</caption>
* const positive = new Converter(
* (input) => typeof input === 'number' && input > 0,
* (input) => input === 0 ? 0.1 : 0.2
* );
*
* positive
* .undefined(() => 0.3)
* .boolean((i) => i ? 1 : 0.4)
* .number(function(i) {
* const result = Math.abs(i)
* return this.is(result) ? result : this.fallback(i);
* })
* .string((i) => positive.convert(Number(i)))
* .symbol((i) => positive.convert(Symbol.keyFor(i)))
* .bigint((i) => positive.convert(Number(i)))
* .register(Array.isArray, (i) => positive.convert(i[0]))
* .register((i) => i === null, (i) => 0.5);
*
* positive.convert(1); // 1
* positive.convert(0); // 0.1 (fallback)
* positive.convert(NaN); // 0.2 (fallback)
* positive.convert(undefined); // 0.3 (has own handler)
* positive.convert(false); // 0.4 (has own handler)
* positive.convert(null); // 0.5 (has own handler)
* positive.convert(2n); // 2
* positive.convert(-3); // 3
* positive.convert('4'); // 4
* positive.convert([5, 6]); // 5
*
* @example <caption>conversion with prohibited input types</caption>
* const converter = new Converter(
* (input) => typeof input === 'number',
* (input) => {
* throw new Error('unknown input data type:' + input);
* })
* .string((i) => {
* throw new Error('string input is forbidden:' + i);
* })
* .boolean(Number)
* .register(Array.isArray, (i) => converter.convert(i[0]));
*
* converter.convert(true); // 1
* converter.convert(2); // 2
* converter.convert('3'); // Error
* converter.convert([4]); // 4
* converter.convert(Promise.resolve(5)); // Error
*/
export declare class Converter<OUTPUT> {
static InvalidTypeCheckFunction: {
new (message?: string | undefined, value?: unknown, options?: unknown): {
value?: unknown;
throw(): void;
name: string;
message: string;
stack?: string | undefined;
};
captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void;
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
stackTraceLimit: number;
};
static InvalidFallbackFunction: {
new (message?: string | undefined, value?: unknown, options?: unknown): {
value?: unknown;
throw(): void;
name: string;
message: string;
stack?: string | undefined;
};
captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void;
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
stackTraceLimit: number;
};
static InvalidConversionFunction: {
new (message?: string | undefined, value?: unknown, options?: unknown): {
value?: unknown;
throw(): void;
name: string;
message: string;
stack?: string | undefined;
};
captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void;
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
stackTraceLimit: number;
};
static InvalidConverter: {
new (message?: string | undefined, value?: unknown, options?: unknown): {
value?: unknown;
throw(): void;
name: string;
message: string;
stack?: string | undefined;
};
captureStackTrace(targetObject: object, constructorOpt?: Function | undefined): void;
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
stackTraceLimit: number;
};
protected _is: IS<OUTPUT>;
protected _fallback: Fallback<OUTPUT>;
protected _types: Partial<TypeConversions<OUTPUT>>;
protected _conversions: Map<IS<any>, Conversion<any, OUTPUT>>;
/**
* @param {IS<OUTPUT>} is - initial input data type check (predicate). determines if any conversion is necessary
* @param {Fallback<OUTPUT>} fallback - fallback value generator. runs if none of the available conversions are suitable
*/
constructor(is: IS<OUTPUT>, fallback: Fallback<OUTPUT>);
get is(): IS<OUTPUT>;
set is(is: IS<OUTPUT>);
get fallback(): Fallback<OUTPUT>;
set fallback(fallback: Fallback<OUTPUT>);
get types(): Partial<TypeConversions<OUTPUT>>;
get conversions(): Array<[IS<unknown>, Conversion<unknown, OUTPUT>]>;
/**
* @description converts data according to saved conversion rules
* @param {*} input - input data
*/
convert: (input?: unknown) => OUTPUT;
/**
* @description adds conversion function for `INPUT` type
* @param {IS<INPUT>} is - input data type check (predicate), determines if input can be processed by `conversion`
* @param {Conversion<INPUT, OUTPUT>} conversion - `INPUT` to `OUTPUT` conversion function
*/
register<INPUT>(is: IS<INPUT>, conversion: Conversion<INPUT, OUTPUT>): this;
/**
* @description removes conversion for `INPUT` type
* @param {IS<INPUT>} is - input type check (predicate)
*/
unregister<INPUT>(is: IS<INPUT>): this;
/**
* @description set conversion rule for type `name` if `conversion` is defined or unset if undefined
* @param {string} name - one of types (`typeof` result)
* @param {Conversion} [conversion]
*/
type<Name extends keyof TypesMap>(name: Name, conversion?: TypeConversion<Name, OUTPUT>): this;
/**
* @description conversion rule setter for `undefined` input
* @param {Conversion} [conversion]
*/
undefined(conversion?: Conversion<undefined, OUTPUT>): this;
/**
* @description conversion rule setter for `boolean` input
* @param {Conversion} [conversion]
*/
boolean(conversion?: Conversion<boolean, OUTPUT>): this;
/**
* @description conversion rule setter for `number` input
* @param {Conversion} [conversion]
*/
number(conversion?: Conversion<number, OUTPUT>): this;
/**
* @description conversion rule setter for `bigint` input
* @param {Conversion} [conversion]
*/
bigint(conversion?: Conversion<bigint, OUTPUT>): this;
/**
* @description conversion rule setter for `string` input
* @param {Conversion} [conversion]
*/
string(conversion?: Conversion<string, OUTPUT>): this;
/**
* @description conversion rule setter for `symbol` input
* @param {Conversion} [conversion]
*/
symbol(conversion?: Conversion<symbol, OUTPUT>): this;
/**
* @example
* const converter = new Converter(
* (i) => typeof i === 'number',
* () => 0
* )
* .undefined(() => 1);
*
* const clone = converter
* .clone()
* .undefined(() => 2);
*
* converter.convert(); // 1
* clone.convert(); // 2
*/
clone(): Converter<OUTPUT>;
static build<OUTPUT>(is: IS<OUTPUT>, fallback: Fallback<OUTPUT>, types?: Partial<TypeConversions<OUTPUT>>, conversions?: Iterable<[IS<any>, Conversion<any, OUTPUT>]>): Converter<OUTPUT>;
static is: (input?: unknown) => boolean;
static assert(input?: unknown): boolean;
}
export default Converter;
//# sourceMappingURL=Converter.d.ts.map