Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: simplify base class hierarchy #1543

Merged
merged 1 commit into from
Dec 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
518 changes: 315 additions & 203 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/extending.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Note that `addMethod` isn't magic, it mutates the prototype of the passed in sch

If you're use case calls for creating an entirely new type. inheriting from
and existing schema class may be best: Generally you should not inheriting from
the abstract `BaseSchema` unless you know what you are doing. The other types are fair game though.
the abstract `Schema` unless you know what you are doing. The other types are fair game though.

You should keep in mind some basic guidelines when extending schemas:

Expand Down
6 changes: 3 additions & 3 deletions src/Lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
SchemaLazyDescription,
} from './schema';
import { Flags, ISchema } from './util/types';
import { BaseSchema } from '.';
import { Schema } from '.';

export type LazyBuilder<
T,
Expand Down Expand Up @@ -60,8 +60,8 @@ class Lazy<T, TContext = AnyObject, TDefault = any, TFlags extends Flags = any>
private _resolve = (
value: any,
options: ResolveOptions<TContext> = {},
): BaseSchema<T, TContext, TDefault, TFlags> => {
let schema = this.builder(value, options) as BaseSchema<
): Schema<T, TContext, TDefault, TFlags> => {
let schema = this.builder(value, options) as Schema<
T,
TContext,
TDefault,
Expand Down
6 changes: 3 additions & 3 deletions src/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
ISchema,
UnsetFlag,
} from './util/types';
import BaseSchema, { SchemaInnerTypeDescription, SchemaSpec } from './schema';
import Schema, { SchemaInnerTypeDescription, SchemaSpec } from './schema';
import { ResolveOptions } from './Condition';

export type RejectorFn = (
Expand All @@ -43,7 +43,7 @@ export default class ArraySchema<
TDefault = undefined,
TFlags extends Flags = '',
TIn extends any[] | null | undefined = T[] | undefined,
> extends BaseSchema<TIn, TContext, TDefault, TFlags> {
> extends Schema<TIn, TContext, TDefault, TFlags> {
innerType?: ISchema<T, TContext>;

constructor(type?: ISchema<T, TContext>) {
Expand Down Expand Up @@ -289,7 +289,7 @@ export default interface ArraySchema<
TDefault = undefined,
TFlags extends Flags = '',
TIn extends any[] | null | undefined = T[] | undefined,
> extends BaseSchema<TIn, TContext, TDefault, TFlags> {
> extends Schema<TIn, TContext, TDefault, TFlags> {
default<D extends Maybe<TIn>>(
def: Thunk<D>,
): ArraySchema<T, TContext, D, ToggleDefault<TFlags, D>, TIn>;
Expand Down
4 changes: 2 additions & 2 deletions src/boolean.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BaseSchema from './schema';
import Schema from './schema';
import type { AnyObject, Maybe, Message, Optionals } from './types';
import type {
Defined,
Expand Down Expand Up @@ -26,7 +26,7 @@ export default class BooleanSchema<
TContext = AnyObject,
TDefault = undefined,
TFlags extends Flags = '',
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
> extends Schema<TType, TContext, TDefault, TFlags> {
constructor() {
super({
type: 'boolean',
Expand Down
6 changes: 3 additions & 3 deletions src/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type {
ToggleDefault,
UnsetFlag,
} from './util/types';
import BaseSchema from './schema';
import Schema from './schema';

let invalidDate = new Date('');

Expand All @@ -34,7 +34,7 @@ export default class DateSchema<
TContext = AnyObject,
TDefault = undefined,
TFlags extends Flags = '',
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
> extends Schema<TType, TContext, TDefault, TFlags> {
static INVALID_DATE = invalidDate;

constructor() {
Expand Down Expand Up @@ -113,7 +113,7 @@ export default interface DateSchema<
TContext = AnyObject,
TDefault = undefined,
TFlags extends Flags = '',
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
> extends Schema<TType, TContext, TDefault, TFlags> {
default<D extends Maybe<TType>>(
def: Thunk<D>,
): DateSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;
Expand Down
12 changes: 6 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Mixed, {
import MixedSchema, {
create as mixedCreate,
MixedSchema,
MixedOptions,
TypeGuard,
} from './mixed';
import BooleanSchema, { create as boolCreate } from './boolean';
import StringSchema, { create as stringCreate } from './string';
Expand All @@ -15,7 +15,7 @@ import ValidationError from './ValidationError';
import reach from './util/reach';
import isSchema from './util/isSchema';
import setLocale from './setLocale';
import BaseSchema, { AnySchema } from './schema';
import Schema, { AnySchema } from './schema';
import type { InferType } from './util/types';

function addMethod<T extends AnySchema>(
Expand Down Expand Up @@ -48,6 +48,7 @@ export type {
InferType as Asserts,
AnySchema,
MixedOptions,
TypeGuard,
};

export {
Expand All @@ -69,9 +70,8 @@ export {
};

export {
BaseSchema,
Mixed as MixedSchema,
MixedSchema as MixedSchemaClass,
Schema,
MixedSchema,
BooleanSchema,
StringSchema,
NumberSchema,
Expand Down
55 changes: 33 additions & 22 deletions src/mixed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,42 @@ import type {
ToggleDefault,
UnsetFlag,
} from './util/types';
import BaseSchema from './schema';
import Schema from './schema';

export declare class MixedSchema<
const returnsTrue: any = () => true;

export type TypeGuard<TType> = (value: any) => value is NonNullable<TType>;
export interface MixedOptions<TType> {
type?: string;
check?: TypeGuard<TType>;
}
export function create<TType = any>(
spec?: MixedOptions<TType> | TypeGuard<TType>,
) {
return new MixedSchema<TType | undefined>(spec);
}

export default class MixedSchema<
TType = any,
TContext = AnyObject,
TDefault = undefined,
TFlags extends Flags = '',
> extends Schema<TType, TContext, TDefault, TFlags> {
constructor(spec?: MixedOptions<TType> | TypeGuard<TType>) {
super(
typeof spec === 'function'
? { type: 'mixed', check: spec }
: { type: 'mixed', check: returnsTrue as TypeGuard<TType>, ...spec },
);
}
}

export default interface MixedSchema<
TType = any,
TContext = AnyObject,
TDefault = undefined,
TFlags extends Flags = '',
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
> extends Schema<TType, TContext, TDefault, TFlags> {
default<D extends Maybe<TType>>(
def: Thunk<D>,
): MixedSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;
Expand All @@ -24,7 +52,7 @@ export declare class MixedSchema<
schema: MixedSchema<IT, IC, ID, IF>,
): MixedSchema<Concat<TType, IT>, TContext & IC, ID, TFlags | IF>;
concat<IT, IC, ID, IF extends Flags>(
schema: BaseSchema<IT, IC, ID, IF>,
schema: Schema<IT, IC, ID, IF>,
): MixedSchema<Concat<TType, IT>, TContext & IC, ID, TFlags | IF>;
concat(schema: this): this;

Expand Down Expand Up @@ -52,21 +80,4 @@ export declare class MixedSchema<
): MixedSchema<TType, TContext, TDefault, SetFlag<TFlags, 's'>>;
}

const Mixed: typeof MixedSchema = BaseSchema as any;

export default Mixed;

export type TypeGuard<TType> = (value: any) => value is NonNullable<TType>;
export interface MixedOptions<TType> {
type?: string;
check?: TypeGuard<TType>;
}
export function create<TType = any>(
spec?: MixedOptions<TType> | TypeGuard<TType>,
) {
return new Mixed<TType | undefined>(
typeof spec === 'function' ? { check: spec } : spec,
);
}
// XXX: this is using the Base schema so that `addMethod(mixed)` works as a base class
create.prototype = Mixed.prototype;
create.prototype = MixedSchema.prototype;
6 changes: 3 additions & 3 deletions src/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
ToggleDefault,
UnsetFlag,
} from './util/types';
import BaseSchema from './schema';
import Schema from './schema';

let isNaN = (value: Maybe<number>) => value != +value!;

Expand All @@ -30,7 +30,7 @@ export default class NumberSchema<
TContext = AnyObject,
TDefault = undefined,
TFlags extends Flags = '',
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
> extends Schema<TType, TContext, TDefault, TFlags> {
constructor() {
super({
type: 'number',
Expand Down Expand Up @@ -156,7 +156,7 @@ export default interface NumberSchema<
TContext = AnyObject,
TDefault = undefined,
TFlags extends Flags = '',
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
> extends Schema<TType, TContext, TDefault, TFlags> {
default<D extends Maybe<TType>>(
def: Thunk<D>,
): NumberSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;
Expand Down
14 changes: 6 additions & 8 deletions src/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { InternalOptions, Callback, Maybe, Message } from './types';
import ValidationError from './ValidationError';
import type { Defined, Thunk, NotNull, _ } from './util/types';
import type Reference from './Reference';
import BaseSchema, { SchemaObjectDescription, SchemaSpec } from './schema';
import Schema, { SchemaObjectDescription, SchemaSpec } from './schema';
import { ResolveOptions } from './Condition';
import type {
AnyObject,
Expand Down Expand Up @@ -74,7 +74,7 @@ export default interface ObjectSchema<
// will match object schema regardless of defaults
TDefault = any,
TFlags extends Flags = '',
> extends BaseSchema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {
> extends Schema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {
default<D extends Maybe<AnyObject>>(
def: Thunk<D>,
): ObjectSchema<TIn, TContext, D, ToggleDefault<TFlags, 'd'>>;
Expand Down Expand Up @@ -105,7 +105,7 @@ export default class ObjectSchema<
TContext = AnyObject,
TDefault = any,
TFlags extends Flags = '',
> extends BaseSchema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {
> extends Schema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {
fields: Shape<NonNullable<TIn>, TContext> = Object.create(null);

declare spec: ObjectSchemaSpec;
Expand Down Expand Up @@ -184,7 +184,7 @@ export default class ObjectSchema<
parent: intermediateValue,
});

let fieldSpec = field instanceof BaseSchema ? field.spec : undefined;
let fieldSpec = field instanceof Schema ? field.spec : undefined;
let strict = fieldSpec?.strict;

if (fieldSpec?.strip) {
Expand Down Expand Up @@ -391,7 +391,7 @@ export default class ObjectSchema<
partial() {
const partial: any = {};
for (const [key, schema] of Object.entries(this.fields)) {
partial[key] = schema instanceof BaseSchema ? schema.optional() : schema;
partial[key] = schema instanceof Schema ? schema.optional() : schema;
}

return this.setFields<Partial<TIn>, TDefault>(partial);
Expand All @@ -401,9 +401,7 @@ export default class ObjectSchema<
const partial: any = {};
for (const [key, schema] of Object.entries(this.fields)) {
if (schema instanceof ObjectSchema) partial[key] = schema.deepPartial();
else
partial[key] =
schema instanceof BaseSchema ? schema.optional() : schema;
else partial[key] = schema instanceof Schema ? schema.optional() : schema;
}
return this.setFields<PartialDeep<TIn>, TDefault>(partial);
}
Expand Down
Loading