type-assurance
Version:
Lightweight type guards and assertions
86 lines (85 loc) • 3.46 kB
TypeScript
/**
* Marker for optional properties.
*/
declare const OPTIONAL: "type-assurance:optional";
/**
* Runtime type definition.
*/
export type Schema = StringConstructor | NumberConstructor | BooleanConstructor | ReadonlyArray<Schema> | {
[prop: string]: Schema;
} | (new (...args: any) => any) | ((v: unknown) => boolean) | string | number | boolean | null | undefined;
/**
* Type to get the actual type from a schema.
*/
export type TypeFromSchema<T> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BooleanConstructor ? boolean : T extends ReadonlyArray<Schema> ? {
[P in keyof T]: TypeFromSchema<T[P]>;
} : T extends {
[key: string]: Schema;
} ? Expand<OptionalProps<T> & RequiredProps<T>> : T extends new (...args: any) => infer R ? R : T extends (v: unknown) => v is infer R ? R : T;
/**
* Expand mapped types for better readability.
* See https://github.com/microsoft/TypeScript/issues/47980
*/
type Expand<T> = T extends unknown ? {
[K in keyof T]: T[K];
} : never;
/**
* Extract only the optional props of a schema.
*/
type OptionalProps<T> = {
-readonly [K in keyof T as T[K] extends {
[OPTIONAL]: true;
} ? K : never]?: TypeFromSchema<T[K]>;
};
/**
* Extract only the required props of a schema.
*/
type RequiredProps<T> = {
-readonly [K in keyof T as T[K] extends {
[OPTIONAL]: true;
} ? never : K]: TypeFromSchema<T[K]>;
};
/**
* Type guard to check if a value is compatible with a given schema.
*/
export declare function is<const T extends Schema>(value: unknown, schema: T): value is TypeFromSchema<T>;
/**
* Compares a value to a schema and returns all property paths
* where the data does not match the specified type.
*/
export declare function diff<const T extends Schema>(value: unknown, schema: T, path?: string): Array<string>;
/**
* Creates a type guard that checks if a value matches the given schema.
*/
export declare function typeGuard<const T extends Schema>(schema: T): (value: unknown) => value is TypeFromSchema<T>;
/**
* Creates a type guard that checks if a value matches any of the given schemas.
*/
export declare function union<T extends Schema[]>(...schemas: T): (v: unknown) => v is TypeFromSchema<T[number]>;
/**
* Creates a type guard that checks if a value either matches the given schema or is undefined.
* The returned function is marked with the `type-assurance:optional` marker – when used as value inside an
* object, the property will become optional.
*/
export declare function optional<T extends Schema>(schema: T): ((v: unknown) => v is TypeFromSchema<T> | undefined) & {
[OPTIONAL]: true;
};
/**
* Type guard that always returns `true`. Can be used to create schemas
* where the type of a property does not matter.
*/
export declare function unknown(v: unknown): v is unknown;
/**
* Asserts that a value matches a given schema.
* @throws TypeError if the value does not match the schema.
*/
export declare function assert<T extends Schema>(value: unknown, schema: T): asserts value is TypeFromSchema<T>;
/**
* Valid Record keys
*/
export type RecordKeys = StringConstructor | NumberConstructor | string | number;
/**
* Creates a type guard that checks if a value matches a given Record<K, V>.
*/
export declare function record<const K extends RecordKeys, const V extends Schema>(key: K, value: V): (v: unknown) => v is Record<TypeFromSchema<K>, TypeFromSchema<V>>;
export {};