Skip to content

Commit

Permalink
Followups (#1924)
Browse files Browse the repository at this point in the history
* feat: expose default locale

* fix(types): fix add method type not accepting valid schema

* fix: revert when types to simpler, less accurate but functional types.

* fix up types
  • Loading branch information
jquense authored Feb 25, 2023
1 parent 3bd5ed9 commit 60fe3b0
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 85 deletions.
52 changes: 21 additions & 31 deletions src/Condition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ import isSchema from './util/isSchema';
import Reference from './Reference';
import type { ISchema } from './types';

export type ConditionBuilder<
T extends ISchema<any, any>,
U extends ISchema<any, any> = T,
> = (values: any[], schema: T, options: ResolveOptions) => U;

export type ConditionConfig<
T extends ISchema<any>,
TThen extends ISchema<any, any> = T,
TOtherwise extends ISchema<any, any> = T,
> = {
export type ConditionBuilder<T extends ISchema<any, any>> = (
values: any[],
schema: T,
options: ResolveOptions,
) => ISchema<any>;

export type ConditionConfig<T extends ISchema<any>> = {
is: any | ((...values: any[]) => boolean);
then?: (schema: T) => TThen;
otherwise?: (schema: T) => TOtherwise;
then?: (schema: T) => ISchema<any>;
otherwise?: (schema: T) => ISchema<any>;
};

export type ResolveOptions<TContext = any> = {
Expand All @@ -23,17 +20,13 @@ export type ResolveOptions<TContext = any> = {
context?: TContext;
};

class Condition<
TIn extends ISchema<any, any> = ISchema<any, any>,
TOut extends ISchema<any, any> = TIn,
> {
fn: ConditionBuilder<TIn, TOut>;

static fromOptions<
TIn extends ISchema<any, any>,
TThen extends ISchema<any, any>,
TOtherwise extends ISchema<any, any>,
>(refs: Reference[], config: ConditionConfig<TIn, TThen, TOtherwise>) {
class Condition<TIn extends ISchema<any, any> = ISchema<any, any>> {
fn: ConditionBuilder<TIn>;

static fromOptions<TIn extends ISchema<any, any>>(
refs: Reference[],
config: ConditionConfig<TIn>,
) {
if (!config.then && !config.otherwise)
throw new TypeError(
'either `then:` or `otherwise:` is required for `when()` conditions',
Expand All @@ -46,19 +39,16 @@ class Condition<
? is
: (...values: any[]) => values.every((value) => value === is);

return new Condition<TIn, TThen | TOtherwise>(
refs,
(values, schema: any) => {
let branch = check(...values) ? then : otherwise;
return new Condition<TIn>(refs, (values, schema: any) => {
let branch = check(...values) ? then : otherwise;

return branch?.(schema) ?? schema;
},
);
return branch?.(schema) ?? schema;
});
}

constructor(
public refs: readonly Reference[],
builder: ConditionBuilder<TIn, TOut>,
builder: ConditionBuilder<TIn>,
) {
this.refs = refs;
this.fn = builder;
Expand Down
6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ValidationError from './ValidationError';
import reach, { getIn } from './util/reach';
import isSchema from './util/isSchema';
import setLocale, { LocaleObject } from './setLocale';
import defaultLocale from './locale';
import Schema, {
AnySchema,
CastOptions as BaseCastOptions,
Expand All @@ -28,12 +29,12 @@ import Schema, {
} from './schema';
import type { InferType, ISchema, Message, ValidateOptions } from './types';

function addMethod<T extends AnySchema>(
function addMethod<T extends ISchema<any>>(
schemaType: (...arg: any[]) => T,
name: string,
fn: (this: T, ...args: any[]) => T,
): void;
function addMethod<T extends new (...args: any) => AnySchema>(
function addMethod<T extends new (...args: any) => ISchema<any>>(
schemaType: T,
name: string,
fn: (this: InstanceType<T>, ...args: any[]) => InstanceType<T>,
Expand Down Expand Up @@ -90,6 +91,7 @@ export {
isSchema,
addMethod,
setLocale,
defaultLocale,
ValidationError,
};

Expand Down
28 changes: 6 additions & 22 deletions src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -763,29 +763,13 @@ export default abstract class Schema<
return next;
}

when<U extends ISchema<any> = this>(builder: ConditionBuilder<this, U>): U;
when<U extends ISchema<any> = this>(
keys: string | string[],
builder: ConditionBuilder<this, U>,
): U;
when<
UThen extends ISchema<any> = this,
UOtherwise extends ISchema<any> = this,
>(options: ConditionConfig<this, UThen, UOtherwise>): UThen | UOtherwise;
when<
UThen extends ISchema<any> = this,
UOtherwise extends ISchema<any> = this,
>(
keys: string | string[],
options: ConditionConfig<this, UThen, UOtherwise>,
): UThen | UOtherwise;
when(builder: ConditionBuilder<this>): this;
when(keys: string | string[], builder: ConditionBuilder<this>): this;
when(options: ConditionConfig<this>): this;
when(keys: string | string[], options: ConditionConfig<this>): this;
when(
keys:
| string
| string[]
| ConditionBuilder<this, any>
| ConditionConfig<this, any, any>,
options?: ConditionBuilder<this, any> | ConditionConfig<this, any, any>,
keys: string | string[] | ConditionBuilder<this> | ConditionConfig<this>,
options?: ConditionBuilder<this> | ConditionConfig<this>,
) {
if (!Array.isArray(keys) && typeof keys !== 'string') {
options = keys;
Expand Down
69 changes: 39 additions & 30 deletions test/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
mixed,
bool,
reach,
addMethod,
} from '../../src';
import { create as tuple } from '../../src/tuple';
import { create as lazy } from '../../src/Lazy';
Expand Down Expand Up @@ -969,36 +970,38 @@ Object: {
}
}

Conditions: {
// $ExpectType NumberSchema<number | undefined, AnyObject, undefined, ""> | StringSchema<string, AnyObject, undefined, "">
string().when('foo', ([foo], schema) => (foo ? schema.required() : number()));

// $ExpectType StringSchema<string | undefined, AnyObject, undefined, "">
string().when('foo', ([foo], schema) => (foo ? schema.required() : schema));

// $ExpectType NumberSchema<number | undefined, AnyObject, undefined, ""> | StringSchema<string, AnyObject, undefined, "">
string().when('foo', {
is: true,
then: () => number(),
otherwise: (s) => s.required(),
});

const result = object({
foo: bool().defined(),
polyField: mixed<string>().when('foo', {
is: true,
then: () => number(),
otherwise: (s) => s.required(),
}),
}).cast({ foo: true, polyField: '1' });

// $ExpectType { polyField?: string | number | undefined; foo: boolean; }
result;

mixed()
.when('foo', ([foo]) => (foo ? string() : number()))
.min(1);
}
// Conditions: {
// // $ExpectType NumberSchema<number | undefined, AnyObject, undefined, ""> | StringSchema<string, AnyObject, undefined, "">
// string().when('foo', ([foo], schema) => (foo ? schema.required() : number()));

// // $ExpectType StringSchema<string | undefined, AnyObject, undefined, "">
// string()
// .when('foo', ([foo], schema) => (foo ? schema.required() : schema))
// .when('foo', ([foo], schema) => (foo ? schema.required() : schema));

// // $ExpectType NumberSchema<number | undefined, AnyObject, undefined, ""> | StringSchema<string, AnyObject, undefined, "">
// string().when('foo', {
// is: true,
// then: () => number(),
// otherwise: (s) => s.required(),
// });

// const result = object({
// foo: bool().defined(),
// polyField: mixed<string>().when('foo', {
// is: true,
// then: () => number(),
// otherwise: (s) => s.required(),
// }),
// }).cast({ foo: true, polyField: '1' });

// // $ExpectType { polyField?: string | number | undefined; foo: boolean; }
// result;

// mixed()
// .when('foo', ([foo]) => (foo ? string() : number()))
// .min(1);
// }

TypeAssigning: {
const _schema: ObjectSchema<{
Expand Down Expand Up @@ -1036,3 +1039,9 @@ reach: {
// $ExpectType Reference<"foo"> | ISchema<"foo", AnyObject, any, any>
const _3 = reach(obj, 'ref');
}

addMethod: {
addMethod(string, 'foo', function () {
return this.clone();
});
}

0 comments on commit 60fe3b0

Please sign in to comment.