Skip to content

Commit c184dcf

Browse files
authored
feat: simplify base class hierarchy (#1543)
BREAKING CHANGE: `mixed` schema are no longer treated as the base class for other schema types. It hasn't been for a while, but we've done some nasty prototype slinging to make it behave like it was. Now typescript types should be 1 to 1 with the actual classes yup exposes. In general this should not affect anything unless you are extending (via `addMethod` or otherwise) `mixed` prototype. ```diff import { - mixed, + Schema, } from 'yup'; - addMethod(mixed, 'method', impl) + addMethod(Schema, 'method', impl) ```
1 parent 3923039 commit c184dcf

14 files changed

+404
-301
lines changed

README.md

+315-203
Large diffs are not rendered by default.

docs/extending.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Note that `addMethod` isn't magic, it mutates the prototype of the passed in sch
4949

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

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

src/Lazy.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
SchemaLazyDescription,
99
} from './schema';
1010
import { Flags, ISchema } from './util/types';
11-
import { BaseSchema } from '.';
11+
import { Schema } from '.';
1212

1313
export type LazyBuilder<
1414
T,
@@ -60,8 +60,8 @@ class Lazy<T, TContext = AnyObject, TDefault = any, TFlags extends Flags = any>
6060
private _resolve = (
6161
value: any,
6262
options: ResolveOptions<TContext> = {},
63-
): BaseSchema<T, TContext, TDefault, TFlags> => {
64-
let schema = this.builder(value, options) as BaseSchema<
63+
): Schema<T, TContext, TDefault, TFlags> => {
64+
let schema = this.builder(value, options) as Schema<
6565
T,
6666
TContext,
6767
TDefault,

src/array.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
ISchema,
2323
UnsetFlag,
2424
} from './util/types';
25-
import BaseSchema, { SchemaInnerTypeDescription, SchemaSpec } from './schema';
25+
import Schema, { SchemaInnerTypeDescription, SchemaSpec } from './schema';
2626
import { ResolveOptions } from './Condition';
2727

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

4949
constructor(type?: ISchema<T, TContext>) {
@@ -289,7 +289,7 @@ export default interface ArraySchema<
289289
TDefault = undefined,
290290
TFlags extends Flags = '',
291291
TIn extends any[] | null | undefined = T[] | undefined,
292-
> extends BaseSchema<TIn, TContext, TDefault, TFlags> {
292+
> extends Schema<TIn, TContext, TDefault, TFlags> {
293293
default<D extends Maybe<TIn>>(
294294
def: Thunk<D>,
295295
): ArraySchema<T, TContext, D, ToggleDefault<TFlags, D>, TIn>;

src/boolean.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import BaseSchema from './schema';
1+
import Schema from './schema';
22
import type { AnyObject, Maybe, Message, Optionals } from './types';
33
import type {
44
Defined,
@@ -26,7 +26,7 @@ export default class BooleanSchema<
2626
TContext = AnyObject,
2727
TDefault = undefined,
2828
TFlags extends Flags = '',
29-
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
29+
> extends Schema<TType, TContext, TDefault, TFlags> {
3030
constructor() {
3131
super({
3232
type: 'boolean',

src/date.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {
1313
ToggleDefault,
1414
UnsetFlag,
1515
} from './util/types';
16-
import BaseSchema from './schema';
16+
import Schema from './schema';
1717

1818
let invalidDate = new Date('');
1919

@@ -34,7 +34,7 @@ export default class DateSchema<
3434
TContext = AnyObject,
3535
TDefault = undefined,
3636
TFlags extends Flags = '',
37-
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
37+
> extends Schema<TType, TContext, TDefault, TFlags> {
3838
static INVALID_DATE = invalidDate;
3939

4040
constructor() {
@@ -113,7 +113,7 @@ export default interface DateSchema<
113113
TContext = AnyObject,
114114
TDefault = undefined,
115115
TFlags extends Flags = '',
116-
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
116+
> extends Schema<TType, TContext, TDefault, TFlags> {
117117
default<D extends Maybe<TType>>(
118118
def: Thunk<D>,
119119
): DateSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;

src/index.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import Mixed, {
1+
import MixedSchema, {
22
create as mixedCreate,
3-
MixedSchema,
43
MixedOptions,
4+
TypeGuard,
55
} from './mixed';
66
import BooleanSchema, { create as boolCreate } from './boolean';
77
import StringSchema, { create as stringCreate } from './string';
@@ -15,7 +15,7 @@ import ValidationError from './ValidationError';
1515
import reach from './util/reach';
1616
import isSchema from './util/isSchema';
1717
import setLocale from './setLocale';
18-
import BaseSchema, { AnySchema } from './schema';
18+
import Schema, { AnySchema } from './schema';
1919
import type { InferType } from './util/types';
2020

2121
function addMethod<T extends AnySchema>(
@@ -48,6 +48,7 @@ export type {
4848
InferType as Asserts,
4949
AnySchema,
5050
MixedOptions,
51+
TypeGuard,
5152
};
5253

5354
export {
@@ -69,9 +70,8 @@ export {
6970
};
7071

7172
export {
72-
BaseSchema,
73-
Mixed as MixedSchema,
74-
MixedSchema as MixedSchemaClass,
73+
Schema,
74+
MixedSchema,
7575
BooleanSchema,
7676
StringSchema,
7777
NumberSchema,

src/mixed.ts

+33-22
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,42 @@ import type {
88
ToggleDefault,
99
UnsetFlag,
1010
} from './util/types';
11-
import BaseSchema from './schema';
11+
import Schema from './schema';
1212

13-
export declare class MixedSchema<
13+
const returnsTrue: any = () => true;
14+
15+
export type TypeGuard<TType> = (value: any) => value is NonNullable<TType>;
16+
export interface MixedOptions<TType> {
17+
type?: string;
18+
check?: TypeGuard<TType>;
19+
}
20+
export function create<TType = any>(
21+
spec?: MixedOptions<TType> | TypeGuard<TType>,
22+
) {
23+
return new MixedSchema<TType | undefined>(spec);
24+
}
25+
26+
export default class MixedSchema<
27+
TType = any,
28+
TContext = AnyObject,
29+
TDefault = undefined,
30+
TFlags extends Flags = '',
31+
> extends Schema<TType, TContext, TDefault, TFlags> {
32+
constructor(spec?: MixedOptions<TType> | TypeGuard<TType>) {
33+
super(
34+
typeof spec === 'function'
35+
? { type: 'mixed', check: spec }
36+
: { type: 'mixed', check: returnsTrue as TypeGuard<TType>, ...spec },
37+
);
38+
}
39+
}
40+
41+
export default interface MixedSchema<
1442
TType = any,
1543
TContext = AnyObject,
1644
TDefault = undefined,
1745
TFlags extends Flags = '',
18-
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
46+
> extends Schema<TType, TContext, TDefault, TFlags> {
1947
default<D extends Maybe<TType>>(
2048
def: Thunk<D>,
2149
): MixedSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;
@@ -24,7 +52,7 @@ export declare class MixedSchema<
2452
schema: MixedSchema<IT, IC, ID, IF>,
2553
): MixedSchema<Concat<TType, IT>, TContext & IC, ID, TFlags | IF>;
2654
concat<IT, IC, ID, IF extends Flags>(
27-
schema: BaseSchema<IT, IC, ID, IF>,
55+
schema: Schema<IT, IC, ID, IF>,
2856
): MixedSchema<Concat<TType, IT>, TContext & IC, ID, TFlags | IF>;
2957
concat(schema: this): this;
3058

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

55-
const Mixed: typeof MixedSchema = BaseSchema as any;
56-
57-
export default Mixed;
58-
59-
export type TypeGuard<TType> = (value: any) => value is NonNullable<TType>;
60-
export interface MixedOptions<TType> {
61-
type?: string;
62-
check?: TypeGuard<TType>;
63-
}
64-
export function create<TType = any>(
65-
spec?: MixedOptions<TType> | TypeGuard<TType>,
66-
) {
67-
return new Mixed<TType | undefined>(
68-
typeof spec === 'function' ? { check: spec } : spec,
69-
);
70-
}
71-
// XXX: this is using the Base schema so that `addMethod(mixed)` works as a base class
72-
create.prototype = Mixed.prototype;
83+
create.prototype = MixedSchema.prototype;

src/number.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type {
1212
ToggleDefault,
1313
UnsetFlag,
1414
} from './util/types';
15-
import BaseSchema from './schema';
15+
import Schema from './schema';
1616

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

@@ -30,7 +30,7 @@ export default class NumberSchema<
3030
TContext = AnyObject,
3131
TDefault = undefined,
3232
TFlags extends Flags = '',
33-
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
33+
> extends Schema<TType, TContext, TDefault, TFlags> {
3434
constructor() {
3535
super({
3636
type: 'number',
@@ -156,7 +156,7 @@ export default interface NumberSchema<
156156
TContext = AnyObject,
157157
TDefault = undefined,
158158
TFlags extends Flags = '',
159-
> extends BaseSchema<TType, TContext, TDefault, TFlags> {
159+
> extends Schema<TType, TContext, TDefault, TFlags> {
160160
default<D extends Maybe<TType>>(
161161
def: Thunk<D>,
162162
): NumberSchema<TType, TContext, D, ToggleDefault<TFlags, D>>;

src/object.ts

+6-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { InternalOptions, Callback, Maybe, Message } from './types';
1717
import ValidationError from './ValidationError';
1818
import type { Defined, Thunk, NotNull, _ } from './util/types';
1919
import type Reference from './Reference';
20-
import BaseSchema, { SchemaObjectDescription, SchemaSpec } from './schema';
20+
import Schema, { SchemaObjectDescription, SchemaSpec } from './schema';
2121
import { ResolveOptions } from './Condition';
2222
import type {
2323
AnyObject,
@@ -74,7 +74,7 @@ export default interface ObjectSchema<
7474
// will match object schema regardless of defaults
7575
TDefault = any,
7676
TFlags extends Flags = '',
77-
> extends BaseSchema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {
77+
> extends Schema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {
7878
default<D extends Maybe<AnyObject>>(
7979
def: Thunk<D>,
8080
): ObjectSchema<TIn, TContext, D, ToggleDefault<TFlags, 'd'>>;
@@ -105,7 +105,7 @@ export default class ObjectSchema<
105105
TContext = AnyObject,
106106
TDefault = any,
107107
TFlags extends Flags = '',
108-
> extends BaseSchema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {
108+
> extends Schema<MakeKeysOptional<TIn>, TContext, TDefault, TFlags> {
109109
fields: Shape<NonNullable<TIn>, TContext> = Object.create(null);
110110

111111
declare spec: ObjectSchemaSpec;
@@ -184,7 +184,7 @@ export default class ObjectSchema<
184184
parent: intermediateValue,
185185
});
186186

187-
let fieldSpec = field instanceof BaseSchema ? field.spec : undefined;
187+
let fieldSpec = field instanceof Schema ? field.spec : undefined;
188188
let strict = fieldSpec?.strict;
189189

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

397397
return this.setFields<Partial<TIn>, TDefault>(partial);
@@ -401,9 +401,7 @@ export default class ObjectSchema<
401401
const partial: any = {};
402402
for (const [key, schema] of Object.entries(this.fields)) {
403403
if (schema instanceof ObjectSchema) partial[key] = schema.deepPartial();
404-
else
405-
partial[key] =
406-
schema instanceof BaseSchema ? schema.optional() : schema;
404+
else partial[key] = schema instanceof Schema ? schema.optional() : schema;
407405
}
408406
return this.setFields<PartialDeep<TIn>, TDefault>(partial);
409407
}

0 commit comments

Comments
 (0)