diff --git a/src/index.ts b/src/index.ts index 51a8c701..dec3c7cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,4 +15,3 @@ export * from './lib/errors/UnknownPropertyError'; export * from './lib/errors/ValidationError'; export * from './lib/Result'; export * from './type-exports'; -export * from './utility-types'; diff --git a/src/lib/Shapes.ts b/src/lib/Shapes.ts index 4369f4a1..601325c0 100644 --- a/src/lib/Shapes.ts +++ b/src/lib/Shapes.ts @@ -1,4 +1,5 @@ import type { TypedArray, TypedArrayName } from '../constraints/util/typedArray'; +import type { Unwrap, UnwrapTuple } from '../lib/util-types'; import { ArrayValidator, BaseValidator, @@ -161,6 +162,3 @@ export class Shapes { return new MapValidator(keyValidator, valueValidator); } } - -export type UnwrapTuple = T extends [infer Head, ...infer Tail] ? [Unwrap, ...UnwrapTuple] : []; -export type Unwrap = T extends BaseValidator ? V : never; diff --git a/src/lib/util-types.ts b/src/lib/util-types.ts index 60e88e5b..8f1ae027 100644 --- a/src/lib/util-types.ts +++ b/src/lib/util-types.ts @@ -1,18 +1,123 @@ import type { BaseValidator } from '../validators/BaseValidator'; +import type { ObjectValidator } from '../validators/ObjectValidator'; export type Constructor = (new (...args: readonly any[]) => T) | (abstract new (...args: readonly any[]) => T); export type Type = V extends BaseValidator ? T : never; -type PickDefined = { [K in keyof T as undefined extends T[K] ? never : K]: T[K] }; +// eslint-disable-next-line @typescript-eslint/ban-types +export type NonNullObject = {} & object; -type PickUndefinedMakeOptional = { +export type PickDefined = { [K in keyof T as undefined extends T[K] ? never : K]: T[K] }; + +export type PickUndefinedMakeOptional = { [K in keyof T as undefined extends T[K] ? K : never]+?: Exclude; }; export type UndefinedToOptional = PickDefined & PickUndefinedMakeOptional; -// eslint-disable-next-line @typescript-eslint/ban-types -export type NonNullObject = {} & object; - export type MappedObjectValidator = { [key in keyof T]: BaseValidator }; + +/** + * An alias of {@link ObjectValidator} with a name more common among object validation libraries. + * This is the type of a schema after using `s.object({ ... })` + * @example + * ```typescript + * import { s, SchemaOf } from '@sapphire/shapeshift'; + * + * interface IIngredient { + * ingredientId: string | undefined; + * name: string | undefined; + * } + * + * interface IInstruction { + * instructionId: string | undefined; + * message: string | undefined; + * } + * + * interface IRecipe { + * recipeId: string | undefined; + * title: string; + * description: string; + * instructions: IInstruction[]; + * ingredients: IIngredient[]; + * } + * + * type InstructionSchemaType = SchemaOf; + * // Expected Type: ObjectValidator + * + * type IngredientSchemaType = SchemaOf; + * // Expected Type: ObjectValidator + * + * type RecipeSchemaType = SchemaOf; + * // Expected Type: ObjectValidator + * + * const instructionSchema: InstructionSchemaType = s.object({ + * instructionId: s.string.optional, + * message: s.string + * }); + * + * const ingredientSchema: IngredientSchemaType = s.object({ + * ingredientId: s.string.optional, + * name: s.string + * }); + * + * const recipeSchema: RecipeSchemaType = s.object({ + * recipeId: s.string.optional, + * title: s.string, + * description: s.string, + * instructions: s.array(instructionSchema), + * ingredients: s.array(ingredientSchema) + * }); + * ``` + */ +export type SchemaOf = ObjectValidator; + +/** + * Infers the type of a schema object given `typeof schema`. + * The schema has to extend {@link ObjectValidator}. + * @example + * ```typescript + * import { InferType, s } from '@sapphire/shapeshift'; + * + * const schema = s.object({ + * foo: s.string, + * bar: s.number, + * baz: s.boolean, + * qux: s.bigint, + * quux: s.date + * }); + * + * type Inferredtype = InferType; + * // Expected type: + * // type Inferredtype = { + * // foo: string; + * // bar: number; + * // baz: boolean; + * // qux: bigint; + * // quux: Date; + * // }; + * ``` + */ +export type InferType> = T extends ObjectValidator ? U : never; + +// +export type UnwrapTuple = T extends [infer Head, ...infer Tail] ? [Unwrap, ...UnwrapTuple] : []; +export type Unwrap = T extends BaseValidator ? V : never; + +// +export type UnshiftTuple = T extends [T[0], ...infer Tail] ? Tail : never; +export type ExpandSmallerTuples = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples : []; + +// https://github.com/microsoft/TypeScript/issues/26223#issuecomment-755067958 +export type Shift> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never; + +export type GrowExpRev, N extends number, P extends Array>> = A['length'] extends N + ? A + : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift

>; + +export type GrowExp, N extends number, P extends Array>> = [...A, ...A][N] extends undefined + ? GrowExp<[...A, ...A], N, [A, ...P]> + : GrowExpRev; + +export type Tuple = number extends N ? Array : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>; diff --git a/src/type-exports.ts b/src/type-exports.ts index 9901624c..d8dbd339 100644 --- a/src/type-exports.ts +++ b/src/type-exports.ts @@ -90,11 +90,11 @@ export type { UnknownEnumValueError } from './lib/errors/UnknownEnumValueError'; export type { UnknownPropertyError } from './lib/errors/UnknownPropertyError'; export type { ValidationError } from './lib/errors/ValidationError'; // -export type { Shapes, Unwrap, UnwrapTuple } from './lib/Shapes'; +export type { Shapes } from './lib/Shapes'; // -export type { Constructor, MappedObjectValidator, NonNullObject, Type } from './lib/util-types'; +export * from './lib/util-types'; // -export type { ArrayValidator, ExpandSmallerTuples, GrowExp, GrowExpRev, Shift, Tuple, UnshiftTuple } from './validators/ArrayValidator'; +export type { ArrayValidator } from './validators/ArrayValidator'; export type { BaseValidator, ValidatorError } from './validators/BaseValidator'; export type { BigIntValidator } from './validators/BigIntValidator'; export type { BooleanValidator } from './validators/BooleanValidator'; diff --git a/src/utility-types.ts b/src/utility-types.ts deleted file mode 100644 index 89b26fff..00000000 --- a/src/utility-types.ts +++ /dev/null @@ -1,84 +0,0 @@ -import type { ObjectValidator } from './validators/ObjectValidator'; - -/** - * An alias of {@link ObjectValidator} with a name more common among object validation libraries. - * This is the type of a schema after using `s.object({ ... })` - * @example - * ```typescript - * import { s, SchemaOf } from '@sapphire/shapeshift'; - * - * interface IIngredient { - * ingredientId: string | undefined; - * name: string | undefined; - * } - * - * interface IInstruction { - * instructionId: string | undefined; - * message: string | undefined; - * } - * - * interface IRecipe { - * recipeId: string | undefined; - * title: string; - * description: string; - * instructions: IInstruction[]; - * ingredients: IIngredient[]; - * } - * - * type InstructionSchemaType = SchemaOf; - * // Expected Type: ObjectValidator - * - * type IngredientSchemaType = SchemaOf; - * // Expected Type: ObjectValidator - * - * type RecipeSchemaType = SchemaOf; - * // Expected Type: ObjectValidator - * - * const instructionSchema: InstructionSchemaType = s.object({ - * instructionId: s.string.optional, - * message: s.string - * }); - * - * const ingredientSchema: IngredientSchemaType = s.object({ - * ingredientId: s.string.optional, - * name: s.string - * }); - * - * const recipeSchema: RecipeSchemaType = s.object({ - * recipeId: s.string.optional, - * title: s.string, - * description: s.string, - * instructions: s.array(instructionSchema), - * ingredients: s.array(ingredientSchema) - * }); - * ``` - */ -export type SchemaOf = ObjectValidator; - -/** - * Infers the type of a schema object given `typeof schema`. - * The schema has to extend {@link ObjectValidator}. - * @example - * ```typescript - * import { InferType, s } from '@sapphire/shapeshift'; - * - * const schema = s.object({ - * foo: s.string, - * bar: s.number, - * baz: s.boolean, - * qux: s.bigint, - * quux: s.date - * }); - * - * type Inferredtype = InferType; - * // Expected type: - * // type Inferredtype = { - * // foo: string; - * // bar: number; - * // baz: boolean; - * // qux: bigint; - * // quux: Date; - * // }; - * ``` - */ -export type InferType> = T extends ObjectValidator ? U : never; diff --git a/src/validators/ArrayValidator.ts b/src/validators/ArrayValidator.ts index 4582c462..c305c978 100644 --- a/src/validators/ArrayValidator.ts +++ b/src/validators/ArrayValidator.ts @@ -14,6 +14,7 @@ import type { BaseError } from '../lib/errors/BaseError'; import { CombinedPropertyError } from '../lib/errors/CombinedPropertyError'; import { ValidationError } from '../lib/errors/ValidationError'; import { Result } from '../lib/Result'; +import type { ExpandSmallerTuples, Tuple, UnshiftTuple } from '../lib/util-types'; import { BaseValidator } from './imports'; export class ArrayValidator extends BaseValidator { @@ -96,19 +97,3 @@ export class ArrayValidator extends BaseVali : Result.err(new CombinedPropertyError(errors)); } } - -export type UnshiftTuple = T extends [T[0], ...infer Tail] ? Tail : never; -export type ExpandSmallerTuples = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples : []; - -// https://github.com/microsoft/TypeScript/issues/26223#issuecomment-755067958 -export type Shift> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never; - -export type GrowExpRev, N extends number, P extends Array>> = A['length'] extends N - ? A - : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift

>; - -export type GrowExp, N extends number, P extends Array>> = [...A, ...A][N] extends undefined - ? GrowExp<[...A, ...A], N, [A, ...P]> - : GrowExpRev; - -export type Tuple = number extends N ? Array : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>;