diff --git a/docs/extending.md b/docs/extending.md index 67e5cc432..0ab60bcd6 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -40,7 +40,7 @@ function parseDateFromFormats(formats, parseStrict) { yup.addMethod(yup.date, 'format', parseDateFromFormats); ``` -Note that `addMethod` isn't really magic, it mutates the prototype of the passed in schema. +Note that `addMethod` isn't magic, it mutates the prototype of the passed in schema. > Note: if you are using TypeScript you also need to adjust the class or interface > see the [typescript](./typescript) docs for details. @@ -49,7 +49,7 @@ Note that `addMethod` isn't really magic, it mutates the prototype of the passed 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 `Schema` unless you know what you are doing. The other types are fair game though. +the abstract `BaseSchema` 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: diff --git a/docs/typescript.md b/docs/typescript.md index b51754476..23bb104f5 100644 --- a/docs/typescript.md +++ b/docs/typescript.md @@ -118,3 +118,13 @@ declare module 'yup' { > Watch out!: If your method needs to adjust schema generics, you likely > need to also extend the Required*, and Defined* interfaces associated with > each basic type. Consult the core types for examples on how to do this + +Be careful of the yup type hierarchy as it's a bit tricky. All schema (including `mixed`) +extend the abstract `BaseSchema` class. + +### Special note about MixedSchema and BaseSchema + +As far as typescript is concerned, `mixed` schema inherit from `BaseSchema` like other schema; all other schema do **not** extend `MixedSchema`. **In actuality** Mixed is an alias for BaseSchema, meaning `addMethod(mixed)` will add a new method to all schema. + +This means that type extensions to `mixed` should generally be put on `BaseSchema` if +you want the method to be available to all sub classes. diff --git a/src/mixed.ts b/src/mixed.ts index 165d72130..1157f2c16 100644 --- a/src/mixed.ts +++ b/src/mixed.ts @@ -4,23 +4,11 @@ import { AnyObject, Maybe, Optionals } from './types'; import type { Defined } from './util/types'; import BaseSchema from './schema'; -export function create() { - return new MixedSchema(); -} - -export default class MixedSchema< +declare class MixedSchema< TType = any, TContext = AnyObject, TOut = TType -> extends BaseSchema {} - -create.prototype = MixedSchema.prototype; - -export default interface MixedSchema< - TType = any, - TContext = AnyObject, - TOut = TType -> { +> extends BaseSchema { default>( def: TNextDefault | (() => TNextDefault), ): TNextDefault extends undefined @@ -46,3 +34,13 @@ export default interface MixedSchema< nullable(isNullable?: true): MixedSchema; nullable(isNullable: false): MixedSchema, TContext>; } + +const Mixed: typeof MixedSchema = BaseSchema as any; + +export default Mixed; + +export function create() { + return new Mixed(); +} +// XXX: this is using the Base schema so that `addMethod(mixed)` works as a base class +create.prototype = Mixed.prototype; diff --git a/test/yup.js b/test/yup.js index 05fdbb0f4..0b1621676 100644 --- a/test/yup.js +++ b/test/yup.js @@ -16,6 +16,8 @@ import { NumberSchema, BooleanSchema, DateSchema, + mixed, + MixedSchema, } from '../src'; describe('Yup', function () { @@ -191,6 +193,18 @@ describe('Yup', function () { }); describe('addMethod', () => { + it('extending mixed should make method accessible everywhere', () => { + addMethod(mixed, 'foo', () => 'here'); + + expect(string().foo()).to.equal('here'); + }); + + it('extending Mixed should make method accessible everywhere', () => { + addMethod(MixedSchema, 'foo', () => 'here'); + + expect(string().foo()).to.equal('here'); + }); + test.each([ ['object', object], ['array', array],