diff --git a/README.md b/README.md index ffbe14a8a..86c1df76f 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ const parsedUser = await userSchema.validate( - [`Schema`](#schema) - [`Schema.clone(): Schema`](#schemaclone-schema) - [`Schema.label(label: string): Schema`](#schemalabellabel-string-schema) - - [`Schema.meta(metadata: object): Schema`](#schemametametadata-object-schema) + - [`Schema.meta(metadata: SchemaMetadata): Schema`](#schemametametadata-schemametadata-schema) - [`Schema.describe(options?: ResolveOptions): SchemaDescription`](#schemadescribeoptions-resolveoptions-schemadescription) - [`Schema.concat(schema: Schema): Schema`](#schemaconcatschema-schema-schema) - [`Schema.validate(value: any, options?: object): Promise, ValidationError>`](#schemavalidatevalue-any-options-object-promiseinfertypeschema-validationerror) @@ -631,10 +631,30 @@ Creates a deep copy of the schema. Clone is used internally to return a new sche Overrides the key name which is used in error messages. -#### `Schema.meta(metadata: object): Schema` +#### `Schema.meta(metadata: SchemaMetadata): Schema` Adds to a metadata object, useful for storing data with a schema, that doesn't belong -the cast object itself. +to the cast object itself. + +A custom `SchemaMetadata` interface can be defined through +[merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces) +with the `CustomSchemaMetadata` interface. Start by creating a `yup.d.ts` file +in your package and creating your desired `CustomSchemaMetadata` interface: + +```ts +// yup.d.ts +import 'yup'; + +declare module 'yup' { + // Define your desired `SchemaMetadata` interface by merging the + // `CustomSchemaMetadata` interface. + export interface CustomSchemaMetadata { + placeholderText?: string + tooltipText?: string + // … + } +} +``` #### `Schema.describe(options?: ResolveOptions): SchemaDescription` diff --git a/src/index.ts b/src/index.ts index 4ad06f91c..cd43c5d14 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,8 @@ import Schema, { SchemaLazyDescription, SchemaFieldDescription, SchemaDescription, + SchemaMetadata, + CustomSchemaMetadata, } from './schema'; import type { InferType, @@ -77,6 +79,8 @@ export type { SchemaLazyDescription, SchemaFieldDescription, SchemaDescription, + SchemaMetadata, + CustomSchemaMetadata, LocaleObject, ValidateOptions, DefaultThunk, diff --git a/src/schema.ts b/src/schema.ts index 99fc6cb42..b8cf53d26 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -44,9 +44,17 @@ export type SchemaSpec = { strict?: boolean; recursive?: boolean; label?: string | undefined; - meta?: any; + meta?: SchemaMetadata; }; +export interface CustomSchemaMetadata {} + +// If `CustomSchemaMeta` isn't extended with any keys, we'll fall back to a +// loose Record definition allowing free form usage. +export type SchemaMetadata = keyof CustomSchemaMetadata extends never + ? Record + : CustomSchemaMetadata; + export type SchemaOptions = { type: string; spec?: Partial>; @@ -111,7 +119,7 @@ export interface SchemaObjectDescription extends SchemaDescription { export interface SchemaLazyDescription { type: string; label?: string; - meta: object | undefined; + meta?: SchemaMetadata; } export type SchemaFieldDescription = @@ -124,7 +132,7 @@ export type SchemaFieldDescription = export interface SchemaDescription { type: string; label?: string; - meta: object | undefined; + meta?: SchemaMetadata; oneOf: unknown[]; notOneOf: unknown[]; default?: unknown; @@ -234,9 +242,9 @@ export default abstract class Schema< return next; } - meta(): Record | undefined; - meta(obj: Record): this; - meta(...args: [Record?]) { + meta(): SchemaMetadata | undefined; + meta(obj: SchemaMetadata): this; + meta(...args: [SchemaMetadata?]) { if (args.length === 0) return this.spec.meta; let next = this.clone();