Skip to content

Commit

Permalink
feat: Allow schema metadata to be strongly typed (#2021)
Browse files Browse the repository at this point in the history
* feat: Allow schema metadata to be strongly typed

* fix: default `SchemaMetadata` typing, export types, update README ToC

---------

Co-authored-by: Shaun Grady <[email protected]>
  • Loading branch information
shaungrady and Shaun Grady authored Jun 15, 2023
1 parent 6dfc75a commit e593f8f
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 9 deletions.
26 changes: 23 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<InferType<Schema>, ValidationError>`](#schemavalidatevalue-any-options-object-promiseinfertypeschema-validationerror)
Expand Down Expand Up @@ -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`

Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import Schema, {
SchemaLazyDescription,
SchemaFieldDescription,
SchemaDescription,
SchemaMetadata,
CustomSchemaMetadata,
} from './schema';
import type {
InferType,
Expand Down Expand Up @@ -77,6 +79,8 @@ export type {
SchemaLazyDescription,
SchemaFieldDescription,
SchemaDescription,
SchemaMetadata,
CustomSchemaMetadata,
LocaleObject,
ValidateOptions,
DefaultThunk,
Expand Down
20 changes: 14 additions & 6 deletions src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,17 @@ export type SchemaSpec<TDefault> = {
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<PropertyKey, any>
: CustomSchemaMetadata;

export type SchemaOptions<TType, TDefault> = {
type: string;
spec?: Partial<SchemaSpec<TDefault>>;
Expand Down Expand Up @@ -111,7 +119,7 @@ export interface SchemaObjectDescription extends SchemaDescription {
export interface SchemaLazyDescription {
type: string;
label?: string;
meta: object | undefined;
meta?: SchemaMetadata;
}

export type SchemaFieldDescription =
Expand All @@ -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;
Expand Down Expand Up @@ -234,9 +242,9 @@ export default abstract class Schema<
return next;
}

meta(): Record<string, unknown> | undefined;
meta(obj: Record<string, unknown>): this;
meta(...args: [Record<string, unknown>?]) {
meta(): SchemaMetadata | undefined;
meta(obj: SchemaMetadata): this;
meta(...args: [SchemaMetadata?]) {
if (args.length === 0) return this.spec.meta;

let next = this.clone();
Expand Down

0 comments on commit e593f8f

Please sign in to comment.