diff --git a/types/yup/index.d.ts b/types/yup/index.d.ts index 25f48e900b..b2b373f9ea 100644 --- a/types/yup/index.d.ts +++ b/types/yup/index.d.ts @@ -11,19 +11,15 @@ // Dan Rumney // Desmond Koh // Maurice de Beijer +// Kalley Powell // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.8 +// TypeScript Version: 3.1 -export function reach( - schema: Schema, - path: string, - value?: any, - context?: any -): Schema; +export function reach(schema: Schema, path: string, value?: any, context?: any): Schema; export function addMethod>( schemaCtor: AnySchemaConstructor, name: string, - method: (this: T, ...args: any[]) => T + method: (this: T, ...args: any[]) => T, ): void; export function ref(path: string, options?: { contextPrefix: string }): Ref; export function lazy(fn: (value: T) => Schema): Lazy; @@ -48,9 +44,9 @@ export type AnySchemaConstructor = | ArraySchemaConstructor | ObjectSchemaConstructor; -export type TestOptionsMessage = +export type TestOptionsMessage = {}, R = any> = | string - | ((params: object & Partial) => string); + | ((params: Extra & Partial) => R); export interface Schema { clone(): this; @@ -73,21 +69,17 @@ export interface Schema { default(value: any): this; default(): T; typeError(message?: TestOptionsMessage): this; - oneOf(arrayOfValues: Array, message?: TestOptionsMessage): this; - notOneOf(arrayOfValues: any[], message?: TestOptionsMessage): this; + oneOf(arrayOfValues: Array, message?: TestOptionsMessage<{ values: T | Ref }>): this; + notOneOf(arrayOfValues: any[], message?: TestOptionsMessage<{ values: T | Ref }>): this; when(keys: string | any[], builder: WhenOptions): this; test( name: string, - message: - | string - | ((params: object & Partial) => string), - test: ( - this: TestContext, - value?: any - ) => boolean | ValidationError | Promise, - callbackStyleAsync?: boolean + message: TestOptionsMessage, + test: (this: TestContext, value?: any) => boolean | ValidationError | Promise, + callbackStyleAsync?: boolean, ): this; - test(options: TestOptions): this; + // tslint:disable-next-line:no-unnecessary-generics + test

(options: TestOptions

): this; transform(fn: TransformFunction): this; } @@ -105,7 +97,7 @@ export interface MixedSchema extends Schema { required(message?: TestOptionsMessage): MixedSchema>; notRequired(): MixedSchema; concat(schema: this): this; - concat(schema: MixedSchema): MixedSchema; + concat(schema: MixedSchema): MixedSchema; } export interface StringSchemaConstructor { @@ -113,19 +105,18 @@ export interface StringSchemaConstructor { new (): StringSchema; } -export interface StringSchema - extends Schema { - length(limit: number | Ref, message?: TestOptionsMessage): StringSchema; - min(limit: number | Ref, message?: TestOptionsMessage): StringSchema; - max(limit: number | Ref, message?: TestOptionsMessage): StringSchema; +export interface StringSchema extends Schema { + length(limit: number | Ref, message?: TestOptionsMessage<{ length: number | Ref }>): StringSchema; + min(limit: number | Ref, message?: TestOptionsMessage<{ min: number | Ref }>): StringSchema; + max(limit: number | Ref, message?: TestOptionsMessage<{ max: number | Ref }>): StringSchema; matches( regex: RegExp, messageOrOptions?: - | TestOptionsMessage - | { message?: TestOptionsMessage; excludeEmptyString?: boolean } + | TestOptionsMessage<{ regex: RegExp }> + | { message?: TestOptionsMessage<{ regex: RegExp }>; excludeEmptyString?: boolean }, ): StringSchema; - email(message?: TestOptionsMessage): StringSchema; - url(message?: TestOptionsMessage): StringSchema; + email(message?: TestOptionsMessage<{ regex: RegExp }>): StringSchema; + url(message?: TestOptionsMessage<{ regex: RegExp }>): StringSchema; ensure(): StringSchema; trim(message?: TestOptionsMessage): StringSchema; lowercase(message?: TestOptionsMessage): StringSchema; @@ -142,23 +133,16 @@ export interface NumberSchemaConstructor { new (): NumberSchema; } -export interface NumberSchema - extends Schema { - min(limit: number | Ref, message?: TestOptionsMessage): NumberSchema; - max(limit: number | Ref, message?: TestOptionsMessage): NumberSchema; - lessThan( - limit: number | Ref, - message?: TestOptionsMessage - ): NumberSchema; - moreThan( - limit: number | Ref, - message?: TestOptionsMessage - ): NumberSchema; - positive(message?: TestOptionsMessage): NumberSchema; - negative(message?: TestOptionsMessage): NumberSchema; +export interface NumberSchema extends Schema { + min(limit: number | Ref, message?: TestOptionsMessage<{ min: number }>): NumberSchema; + max(limit: number | Ref, message?: TestOptionsMessage<{ max: number }>): NumberSchema; + lessThan(limit: number | Ref, message?: TestOptionsMessage<{ less: number }>): NumberSchema; + moreThan(limit: number | Ref, message?: TestOptionsMessage<{ more: number }>): NumberSchema; + positive(message?: TestOptionsMessage<{ more: number }>): NumberSchema; + negative(message?: TestOptionsMessage<{ less: number }>): NumberSchema; integer(message?: TestOptionsMessage): NumberSchema; truncate(): NumberSchema; - round(type: "floor" | "ceil" | "trunc" | "round"): NumberSchema; + round(type: 'floor' | 'ceil' | 'trunc' | 'round'): NumberSchema; nullable(isNullable?: true): NumberSchema; nullable(isNullable: false): NumberSchema>; nullable(isNullable?: boolean): NumberSchema; @@ -171,14 +155,11 @@ export interface BooleanSchemaConstructor { new (): BooleanSchema; } -export interface BooleanSchema - extends Schema { +export interface BooleanSchema extends Schema { nullable(isNullable?: true): BooleanSchema; nullable(isNullable: false): BooleanSchema>; nullable(isNullable?: boolean): BooleanSchema; - required( - message?: TestOptionsMessage - ): BooleanSchema>; + required(message?: TestOptionsMessage): BooleanSchema>; notRequired(): BooleanSchema; } @@ -187,16 +168,9 @@ export interface DateSchemaConstructor { new (): DateSchema; } -export interface DateSchema - extends Schema { - min( - limit: Date | string | Ref, - message?: TestOptionsMessage - ): DateSchema; - max( - limit: Date | string | Ref, - message?: TestOptionsMessage - ): DateSchema; +export interface DateSchema extends Schema { + min(limit: Date | string | Ref, message?: TestOptionsMessage<{ min: Date | string }>): DateSchema; + max(limit: Date | string | Ref, message?: TestOptionsMessage<{ max: Date | string }>): DateSchema; nullable(isNullable?: true): DateSchema; nullable(isNullable: false): DateSchema>; nullable(isNullable?: boolean): DateSchema; @@ -209,22 +183,16 @@ export interface ArraySchemaConstructor { new (): ArraySchema<{}>; } -interface BasicArraySchema - extends Schema { - min(limit: number | Ref, message?: TestOptionsMessage): this; - max(limit: number | Ref, message?: TestOptionsMessage): this; +interface BasicArraySchema extends Schema { + min(limit: number | Ref, message?: TestOptionsMessage<{ min: number }>): this; + max(limit: number | Ref, message?: TestOptionsMessage<{ max: number }>): this; ensure(): this; compact( - rejector?: ( - value: InferredArrayType, - index: number, - array: Array> - ) => boolean + rejector?: (value: InferredArrayType, index: number, array: Array>) => boolean, ): this; } -export interface NotRequiredNullableArraySchema - extends BasicArraySchema { +export interface NotRequiredNullableArraySchema extends BasicArraySchema { of(type: Schema): NotRequiredNullableArraySchema; nullable(isNullable?: true): NotRequiredNullableArraySchema; nullable(isNullable: false): NotRequiredArraySchema; @@ -242,8 +210,7 @@ export interface NullableArraySchema extends BasicArraySchema { notRequired(): NotRequiredNullableArraySchema; } -export interface NotRequiredArraySchema - extends BasicArraySchema { +export interface NotRequiredArraySchema extends BasicArraySchema { of(type: Schema): NotRequiredArraySchema; nullable(isNullable?: true): NotRequiredNullableArraySchema; nullable(isNullable: false): NotRequiredArraySchema; @@ -261,7 +228,7 @@ export interface ArraySchema extends BasicArraySchema { } export type ObjectSchemaDefinition = { - [field in keyof T]: Schema | Ref + [field in keyof T]: Schema | Ref; }; /** @@ -270,7 +237,7 @@ export type ObjectSchemaDefinition = { * [yup's `object.shape()` method](https://www.npmjs.com/package/yup#objectshapefields-object-nosortedges-arraystring-string-schema). */ export type Shape = { - [P in keyof T]: P extends keyof U ? U[P] : T[P] + [P in keyof T]: P extends keyof U ? U[P] : T[P]; } & U; @@ -279,17 +246,13 @@ export interface ObjectSchemaConstructor { new (): ObjectSchema<{}>; } -export interface ObjectSchema - extends Schema { +export interface ObjectSchema extends Schema { shape( fields: ObjectSchemaDefinition, - noSortEdges?: Array<[string, string]> + noSortEdges?: Array<[string, string]>, ): ObjectSchema>; from(fromKey: string, toKey: string, alias?: boolean): ObjectSchema; - noUnknown( - onlyKnownKeys?: boolean, - message?: TestOptionsMessage - ): ObjectSchema; + noUnknown(onlyKnownKeys?: boolean, message?: TestOptionsMessage): ObjectSchema; transformKeys(callback: (key: any) => any): void; camelCase(): ObjectSchema; constantCase(): ObjectSchema; @@ -302,11 +265,7 @@ export interface ObjectSchema concat(schema: ObjectSchema): ObjectSchema; } -export type TransformFunction = ( - this: T, - value: any, - originalValue: any -) => any; +export type TransformFunction = (this: T, value: any, originalValue: any) => any; export interface WhenOptionsBuilderFunction { (value: any, schema: T): T; @@ -315,13 +274,7 @@ export interface WhenOptionsBuilderFunction { (v1: any, v2: any, v3: any, v4: any, schema: T): T; } -export type WhenOptionsBuilderObjectIs = - | ((...values: any[]) => boolean) - | boolean - | number - | null - | object - | string; +export type WhenOptionsBuilderObjectIs = ((...values: any[]) => boolean) | boolean | number | null | object | string; export type WhenOptionsBuilderObject = | { @@ -331,9 +284,7 @@ export type WhenOptionsBuilderObject = } | object; - export type WhenOptions = - | WhenOptionsBuilderFunction - | WhenOptionsBuilderObject; +export type WhenOptions = WhenOptionsBuilderFunction | WhenOptionsBuilderObject; export interface TestContext { path: string; @@ -341,10 +292,7 @@ export interface TestContext { parent: any; schema: Schema; resolve: (value: any) => any; - createError: (params?: { - path?: string; - message?: string; - }) => ValidationError; + createError: (params?: { path?: string; message?: string }) => ValidationError; } export interface ValidateOptions { @@ -377,7 +325,7 @@ export interface TestMessageParams { label: string; } -export interface TestOptions { +export interface TestOptions

= {}, R = any> { /** * Unique name identifying the test */ @@ -386,20 +334,17 @@ export interface TestOptions { /** * Test function, determines schema validity */ - test: ( - this: TestContext, - value: any - ) => boolean | ValidationError | Promise; + test: (this: TestContext, value: any) => boolean | ValidationError | Promise; /** * The validation error message */ - message?: TestOptionsMessage; + message?: TestOptionsMessage; /** * Values passed to message for interpolation */ - params?: object; + params?: P; /** * Mark the test as exclusive, meaning only one of the same can be active at once @@ -441,17 +386,9 @@ export class ValidationError extends Error { params?: object; static isError(err: any): err is ValidationError; - static formatError( - message: string | ((params?: any) => string), - params?: any - ): string | ((params?: any) => string); + static formatError(message: string | ((params?: any) => string), params?: any): string | ((params?: any) => string); - constructor( - errors: string | string[], - value: any, - path: string, - type?: any - ); + constructor(errors: string | string[], value: any, path: string, type?: any); } // It is tempting to declare `Ref` very simply, but there are problems with these approaches: @@ -493,29 +430,35 @@ export interface FormatErrorParams { export type LocaleValue = string | ((params: FormatErrorParams) => string); +type MessageFromParameters

= { + [K in keyof P]: P[K] extends TestOptionsMessage ? P[K] : never; +}[number]; + +type MappedLocaleSchema> = { + [key in keyof S]?: S[key] extends (...args: infer P) => any ? MessageFromParameters> : never; +}; + export interface LocaleObject { - mixed?: { [key in keyof MixedSchema]?: string } & { notType?: LocaleValue }; - string?: { [key in keyof StringSchema]?: string }; - number?: { [key in keyof NumberSchema]?: string }; - boolean?: { [key in keyof BooleanSchema]?: string }; - bool?: { [key in keyof BooleanSchema]?: string }; - date?: { [key in keyof DateSchema]?: string }; - array?: { [key in keyof ArraySchema]?: string }; - object?: { [key in keyof ObjectSchema]?: string }; + mixed?: MappedLocaleSchema & { notType?: LocaleValue }; + string?: MappedLocaleSchema; + number?: MappedLocaleSchema; + boolean?: MappedLocaleSchema; + bool?: MappedLocaleSchema; + date?: MappedLocaleSchema; + array?: MappedLocaleSchema>; + object?: MappedLocaleSchema>; } -export type InferType = T extends Schema - ? InnerInferType

- : never; +export type InferType = T extends Schema ? InnerInferType

: never; // Shut off automatic exporting after this statement export {}; type KeyOfUndefined = { - [P in keyof T]-?: undefined extends T[P] ? P : never + [P in keyof T]-?: undefined extends T[P] ? P : never; }[keyof T]; -type Id = {[K in keyof T]: T[K]}; +type Id = { [K in keyof T]: T[K] }; type RequiredProps = Pick>>; type NotRequiredProps = Partial>>; type InnerInferType = Id & RequiredProps>; diff --git a/types/yup/yup-tests.ts b/types/yup/yup-tests.ts index 093ee6c484..a8d9c8ee0c 100644 --- a/types/yup/yup-tests.ts +++ b/types/yup/yup-tests.ts @@ -143,6 +143,9 @@ mixed.typeError('type error'); mixed.typeError(() => 'type error'); mixed.oneOf(['hello', 'world'], 'message'); mixed.oneOf(['hello', 'world'], () => 'message'); +mixed.oneOf(['hello', 'world'], ({ values }) => `one of ${values}`); +// $ExpectError +mixed.oneOf(['hello', 'world'], ({ random }) => `one of ${random}`); mixed.notOneOf(['hello', 'world'], 'message'); mixed.notOneOf(['hello', 'world'], () => 'message'); mixed.when('isBig', { @@ -198,6 +201,12 @@ mixed.test('with-context', 'it uses function context', testContext); mixed.test({ test: testContext, }); +mixed.test({ + message: ({ passed }) => (passed ? 'You passed' : 'You failed'), + name: 'checkParams', + params: { passed: true }, + test: value => !!value, +}); // mixed with concat yup.object({ name: yup.string() }).concat(yup.object({ when: yup.date() })); // $ExpectType ObjectSchema<{ name: string; } & { when: Date; }> @@ -267,19 +276,31 @@ strSchema.required('req'); strSchema.required(() => 'req'); strSchema.length(5, 'message'); strSchema.length(5, () => 'message'); +strSchema.length(5, ({ length }) => `must be ${length}`); +// $ExpectError +strSchema.length(5, ({ min }) => `must be ${min}`); strSchema.min(5, 'message'); strSchema.min(5, () => 'message'); +strSchema.min(5, ({ min }) => `more than ${min}`); +// $ExpectError +strSchema.min(5, ({ max }) => `more than ${max}`); strSchema.max(5, 'message'); strSchema.max(5, () => 'message'); +strSchema.max(5, ({ max }) => `less than ${max}`); +// $ExpectError +strSchema.max(5, ({ min }) => `less than ${min}`); strSchema.matches(/(hi|bye)/); strSchema.matches(/(hi|bye)/, 'invalid'); strSchema.matches(/(hi|bye)/, () => 'invalid'); +strSchema.matches(/(hi|bye)/, ({ regex }) => `Does not match ${regex}`); strSchema.email(); strSchema.email('invalid'); strSchema.email(() => 'invalid'); +strSchema.email(({ regex }) => `Does not match ${regex}`); strSchema.url(); strSchema.url('bad url'); strSchema.url(() => 'bad url'); +strSchema.url(({ regex }) => `Does not match ${regex}`); strSchema.ensure(); strSchema.trim(); strSchema.trim('trimmed'); @@ -297,9 +318,15 @@ numSchema.isValid(10); // => true numSchema.min(5); numSchema.min(5, 'message'); numSchema.min(5, () => 'message'); +numSchema.min(5, ({ min }) => `more than ${min}`); +// $ExpectError +numSchema.min(5, ({ max }) => `more than ${max}`); numSchema.max(5); numSchema.max(5, 'message'); numSchema.max(5, () => 'message'); +numSchema.max(5, ({ max }) => `less than ${max}`); +// $ExpectError +numSchema.max(5, ({ min }) => `more than ${min}`); numSchema.positive(); numSchema.positive('pos'); numSchema.positive(() => 'pos'); @@ -358,8 +385,8 @@ arrSchema.compact((value, index, array) => value === array[index]); const arrOfObjSchema = yup.array().of( yup.object().shape({ - field: yup.number() - }) + field: yup.number(), + }), ); arrOfObjSchema.compact((value, index, array) => { return value.field > 10 && array[index].field > 10; @@ -462,8 +489,21 @@ const localeNotType3: LocaleObject = { }; yup.setLocale({ + mixed: { + required: options => options, + }, number: { max: 'Max message', min: 'Min message' }, - string: { email: 'String message' }, + string: { + email: 'String message', + length: ({ length }) => ({ key: 'stringLength', options: { length } }), + }, +}); + +yup.setLocale({ + // $ExpectError + string: { + nullable: 'message', + }, }); interface MyInterface { @@ -583,9 +623,7 @@ enum Gender { const personSchema = yup.object({ firstName: yup.string(), // $ExpectType StringSchema - gender: yup - .mixed() - .oneOf([Gender.Male, Gender.Female]), + gender: yup.mixed().oneOf([Gender.Male, Gender.Female]), email: yup .string() .nullable() @@ -685,7 +723,10 @@ castPerson.children = undefined; const loginSchema = yup.object({ password: yup.string(), - confirmPassword: yup.string().nullable().oneOf([yup.ref("password"), null]), + confirmPassword: yup + .string() + .nullable() + .oneOf([yup.ref('password'), null]), }); function wrapper(b: false, msx: MixedSchema): MixedSchema;