{"id":13520490,"url":"https://github.com/sapphiredev/shapeshift","last_synced_at":"2025-04-04T15:09:51.140Z","repository":{"id":36962418,"uuid":"437023480","full_name":"sapphiredev/shapeshift","owner":"sapphiredev","description":"Blazing fast input validation and transformation ⚡","archived":false,"fork":false,"pushed_at":"2024-04-07T09:46:12.000Z","size":14333,"stargazers_count":89,"open_issues_count":5,"forks_count":13,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-04-13T21:01:06.991Z","etag":null,"topics":["checking","hacktoberfest","input-validation","ow","runtime-validation","schema","type-checking","type-validation","validation","zod"],"latest_commit_sha":null,"homepage":"https://www.sapphirejs.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sapphiredev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":["sapphiredev"],"patreon":"sapphire_community","open_collective":"sapphiredev","ko_fi":"sapphirecommunity","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":"https://sapphirejs.dev/paypal"}},"created_at":"2021-12-10T15:21:09.000Z","updated_at":"2024-04-15T01:56:34.715Z","dependencies_parsed_at":"2023-11-21T21:04:43.153Z","dependency_job_id":"08344e10-e25b-4e4c-8da3-a98f7ea76e6d","html_url":"https://github.com/sapphiredev/shapeshift","commit_stats":{"total_commits":437,"total_committers":14,"mean_commits":"31.214285714285715","dds":0.5446224256292906,"last_synced_commit":"27888a2711f75386c3ed9649e49e28f711b148eb"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":"sapphiredev/sapphire-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapphiredev%2Fshapeshift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapphiredev%2Fshapeshift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapphiredev%2Fshapeshift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sapphiredev%2Fshapeshift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sapphiredev","download_url":"https://codeload.github.com/sapphiredev/shapeshift/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246391955,"owners_count":20769659,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["checking","hacktoberfest","input-validation","ow","runtime-validation","schema","type-checking","type-validation","validation","zod"],"created_at":"2024-08-01T05:02:22.332Z","updated_at":"2025-04-04T15:09:51.121Z","avatar_url":"https://github.com/sapphiredev.png","language":"TypeScript","readme":"\u003cdiv align=\"center\"\u003e\n\n![Sapphire Logo](https://raw.githubusercontent.com/sapphiredev/assets/main/banners/SapphireCommunity.png)\n\n# @sapphire/shapeshift\n\n**Shapeshift**\n\nBlazing fast input validation and transformation ⚡\n\n[![GitHub](https://img.shields.io/github/license/sapphiredev/shapeshift)](https://github.com/sapphiredev/shapeshift/blob/main/LICENSE.md)\n[![npm](https://img.shields.io/npm/v/@sapphire/shapeshift?color=crimson\u0026logo=npm\u0026style=flat-square)](https://www.npmjs.com/package/@sapphire/shapeshift)\n\n\u003c/div\u003e\n\n## Table of Contents\n\n- [Table of Contents](#table-of-contents)\n- [Description](#description)\n- [Features](#features)\n- [Usage](#usage)\n  - [Basic usage](#basic-usage)\n  - [Defining validations](#defining-validations)\n    - [Primitives](#primitives)\n    - [Literals](#literals)\n    - [Strings](#strings)\n    - [Numbers](#numbers)\n    - [BigInts](#bigints)\n    - [Booleans](#booleans)\n    - [Arrays](#arrays)\n    - [Tuples](#tuples)\n    - [Unions](#unions)\n    - [Enums](#enums)\n    - [Maps](#maps)\n    - [Sets](#sets)\n    - [Instances](#instances)\n    - [Records](#records)\n    \u003c!-- - [Functions // TODO](#functions--todo) --\u003e\n    - [TypedArray](#typedarray)\n  - [Defining schemas (objects)](#defining-schemas-objects)\n    - [Utility types for TypeScript](#utility-types-for-typescript)\n      - [Extracting an interface from a schema](#extracting-an-interface-from-a-schema)\n      - [Defining the structure of a schema through an interface](#defining-the-structure-of-a-schema-through-an-interface)\n    - [`.extend`:](#extend)\n    - [`.pick` / `.omit`:](#pick--omit)\n    - [`.partial`](#partial)\n    - [`.required`](#required)\n  - [Handling unrecognized keys](#handling-unrecognized-keys)\n    - [`.strict`](#strict)\n    - [`.ignore`](#ignore)\n    - [`.passthrough`](#passthrough)\n  - [BaseValidator: methods and properties](#basevalidator-methods-and-properties)\n    - [`.run(data: unknown): Result`: given a validation, you can call this method to check whether or not the](#rundata-unknown-resultt-error-given-a-validation-you-can-call-this-method-to-check-whether-or-not-the)\n    - [`.parse(data: unknown): T`: given a validations, you can call this method to check whether or not the input is valid.](#parsedata-unknown-t-given-a-validations-you-can-call-this-method-to-check-whether-or-not-the-input-is-valid)\n    - [`.transform((value: T) =\u003e R): NopValidator`: adds a constraint that modifies the input:](#transformrvalue-t--r-nopvalidatorr-adds-a-constraint-that-modifies-the-input)\n    - [`.reshape((value: T) =\u003e Result | IConstraint): NopValidator`: adds a constraint able to both validate](#reshapervalue-t--resultr-error--iconstraint-nopvalidatorr-adds-a-constraint-able-to-both-validate)\n    - [`.default(value: T | (() =\u003e T))`: transform `undefined` into the given value or the callback's returned value:](#defaultvalue-t----t-transform-undefined-into-the-given-value-or-the-callbacks-returned-value)\n    - [`.optional`: a convenience method that returns a union of the type with `s.undefined()`.](#optional-a-convenience-method-that-returns-a-union-of-the-type-with-sundefined)\n    - [`.nullable`: a convenience method that returns a union of the type with `s.nullable()`.](#nullable-a-convenience-method-that-returns-a-union-of-the-type-with-snullable)\n    - [`.nullish`: a convenience method that returns a union of the type with `s.nullish()`.](#nullish-a-convenience-method-that-returns-a-union-of-the-type-with-snullish)\n    - [`.array`: a convenience method that returns an ArrayValidator with the type.](#array-a-convenience-method-that-returns-an-arrayvalidator-with-the-type)\n    - [`.or`: a convenience method that returns an UnionValidator with the type. This method is also overridden in](#or-a-convenience-method-that-returns-an-unionvalidator-with-the-type-this-method-is-also-overridden-in)\n    - [`.when`: Adjust the schema based on a sibling or sinbling children fields.](#when-adjust-the-schema-based-on-a-sibling-or-sinbling-children-fields)\n      - [Available options for providing `is`](#available-options-for-providing-is)\n      - [Resolving of the `key` (first) parameter](#resolving-of-the-key-first-parameter)\n      - [Examples](#examples)\n  - [Enabling and disabling validation](#enabling-and-disabling-validation)\n- [Buy us some doughnuts](#buy-us-some-doughnuts)\n- [Contributors](#contributors)\n\n## Description\n\n[Back to top][toc]\n\nA very fast and lightweight input validation and transformation library for JavaScript.\n\n\u003e **Note**: Shapeshift requires Node.js v14.0.0 or higher to work.\n\n## Features\n\n[Back to top][toc]\n\n- TypeScript friendly\n- Offers CJS, ESM and UMD builds\n- API similar to [`zod`] and [`yup`]\n- Faster than ⚡\n\n## Usage\n\n[Back to top][toc]\n\n**_For complete usages, please dive into our [documentation]_**\n\n### Basic usage\n\n[Back to top][toc]\n\nCreating a simple string validation\n\n```typescript\nimport { s } from '@sapphire/shapeshift';\n\nconst myStringValidation = s.string();\n\n// Parse\nmyStringValidation.parse('sapphire'); // =\u003e returns 'sapphire'\nmyStringValidation.parse(12); // throws ValidationError\n```\n\nCreating an object schema\n\n```typescript\nimport { s } from '@sapphire/shapeshift';\n\nconst user = s.object({\n  username: s.string()\n});\n\nuser.parse({ username: 'Sapphire' });\n```\n\n### Defining validations\n\n[Back to top][toc]\n\n#### Primitives\n\n[Back to top][toc]\n\n```typescript\nimport { s } from '@sapphire/shapeshift';\n\n// Primitives\ns.string();\ns.number();\ns.bigint();\ns.boolean();\ns.date();\n\n// Empty Types\ns.undefined();\ns.null();\ns.nullish(); // Accepts undefined | null\n\n// Catch-all Types\ns.any();\ns.unknown();\n\n// Never Type\ns.never();\n```\n\n#### Literals\n\n[Back to top][toc]\n\n```typescript\ns.literal('sapphire');\ns.literal(12);\ns.literal(420n);\ns.literal(true);\ns.literal(new Date(1639278160000)); // s.date().equal(1639278160000);\n```\n\n#### Strings\n\n[Back to top][toc]\n\nShapeshift includes a handful of string-specific validations:\n\n```typescript\ns.string().lengthLessThan(5);\ns.string().lengthLessThanOrEqual(5);\ns.string().lengthGreaterThan(5);\ns.string().lengthGreaterThanOrEqual(5);\ns.string().lengthEqual(5);\ns.string().lengthNotEqual(5);\ns.string().email();\ns.string().url();\ns.string().uuid();\ns.string().regex(regex);\ns.string().ip();\ns.string().ipv4();\ns.string().ipv6();\ns.string().phone();\n```\n\n#### Numbers\n\n[Back to top][toc]\n\nShapeshift includes a handful of number-specific validations:\n\n```typescript\ns.number().greaterThan(5); // \u003e 5\ns.number().greaterThanOrEqual(5); // \u003e= 5\ns.number().lessThan(5); // \u003c 5\ns.number().lessThanOrEqual(5); // \u003c= 5\ns.number().equal(5); // === 5\ns.number().notEqual(5); // !== 5\n\ns.number().equal(NaN); // special case: Number.isNaN\ns.number().notEqual(NaN); // special case: !Number.isNaN\n\ns.number().int(); // value must be an integer\ns.number().safeInt(); // value must be a safe integer\ns.number().finite(); // value must be finite\n\ns.number().positive(); // .greaterThanOrEqual(0)\ns.number().negative(); // .lessThan(0)\n\ns.number().divisibleBy(5); // Divisible by 5\n```\n\nAnd transformations:\n\n```typescript\ns.number().abs(); // Transforms the number to an absolute number\ns.number().sign(); // Gets the number's sign\n\ns.number().trunc(); // Transforms the number to the result of `Math.trunc`\ns.number().floor(); // Transforms the number to the result of `Math.floor`\ns.number().fround(); // Transforms the number to the result of `Math.fround`\ns.number().round(); // Transforms the number to the result of `Math.round`\ns.number().ceil(); // Transforms the number to the result of `Math.ceil`\n```\n\n#### BigInts\n\n[Back to top][toc]\n\nShapeshift includes a handful of number-specific validations:\n\n```typescript\ns.bigint().greaterThan(5n); // \u003e 5n\ns.bigint().greaterThanOrEqual(5n); // \u003e= 5n\ns.bigint().lessThan(5n); // \u003c 5n\ns.bigint().lessThanOrEqual(5n); // \u003c= 5n\ns.bigint().equal(5n); // === 5n\ns.bigint().notEqual(5n); // !== 5n\n\ns.bigint().positive(); // .greaterThanOrEqual(0n)\ns.bigint().negative(); // .lessThan(0n)\n\ns.bigint().divisibleBy(5n); // Divisible by 5n\n```\n\nAnd transformations:\n\n```typescript\ns.bigint().abs(); // Transforms the bigint to an absolute bigint\n\ns.bigint().intN(5); // Clamps to a bigint to a signed bigint with 5 digits, see BigInt.asIntN\ns.bigint().uintN(5); // Clamps to a bigint to an unsigned bigint with 5 digits, see BigInt.asUintN\n```\n\n#### Booleans\n\n[Back to top][toc]\n\nShapeshift includes a few boolean-specific validations:\n\n```typescript\ns.boolean().true(); // value must be true\ns.boolean().false(); // value must be false\n\ns.boolean().equal(true); // s.boolean().true()\ns.boolean().equal(false); // s.boolean().false()\n\ns.boolean().notEqual(true); // s.boolean().false()\ns.boolean().notEqual(false); // s.boolean().true()\n```\n\n#### Arrays\n\n[Back to top][toc]\n\n```typescript\nconst stringArray = s.array(s.string());\nconst stringArray = s.string().array();\n```\n\nShapeshift includes a handful of array-specific validations:\n\n```typescript\ns.string().array().lengthLessThan(5); // Must have less than 5 elements\ns.string().array().lengthLessThanOrEqual(5); // Must have 5 or less elements\ns.string().array().lengthGreaterThan(5); // Must have more than 5 elements\ns.string().array().lengthGreaterThanOrEqual(5); // Must have 5 or more elements\ns.string().array().lengthEqual(5); // Must have exactly 5 elements\ns.string().array().lengthNotEqual(5); // Must not have exactly 5 elements\ns.string().array().lengthRange(0, 4); // Must have at least 0 elements and less than 4 elements (in math, that is [0, 4))\ns.string().array().lengthRangeInclusive(0, 4); // Must have at least 0 elements and at most 4 elements (in math, that is [0, 4])\ns.string().array().lengthRangeExclusive(0, 4); // Must have more than 0 element and less than 4 elements (in math, that is (0, 4))\ns.string().array().unique(); // All elements must be unique. Deep equality is used to check for uniqueness.\n```\n\n\u003e **Note**: All `.length` methods define tuple types with the given amount of elements. For example,\n\u003e `s.string().array().lengthGreaterThanOrEqual(2)`'s inferred type is `[string, string, ...string[]]`\n\n#### Tuples\n\n[Back to top][toc]\n\nUnlike arrays, tuples have a fixed number of elements and each element can have a different type:\n\n```typescript\nconst dish = s.tuple([\n  s.string(), // Dish's name\n  s.number().int(), // Table's number\n  s.date() // Date the dish was ready for delivery\n]);\n\ndish.parse(['Iberian ham', 10, new Date()]);\n```\n\n#### Unions\n\n[Back to top][toc]\n\nShapeshift includes a built-in method for composing OR types:\n\n```typescript\nconst stringOrNumber = s.union([s.string(), s.number()]);\n\nstringOrNumber.parse('Sapphire'); // =\u003e 'Sapphire'\nstringOrNumber.parse(42); // =\u003e 42\nstringOrNumber.parse({}); // =\u003e throws CombinedError\n```\n\n#### Enums\n\n[Back to top][toc]\n\nEnums are a convenience method that aliases `s.union([s.literal(a), s.literal(b), ...])`:\n\n```typescript\ns.enum(['Red', 'Green', 'Blue']);\n// s.union([s.literal('Red'), s.literal('Green'), s.literal('Blue')]);\n```\n\n#### Maps\n\n[Back to top][toc]\n\n```typescript\nconst map = s.map(s.string(), s.number());\n// Map\u003cstring, number\u003e\n```\n\n#### Sets\n\n[Back to top][toc]\n\n```typescript\nconst set = s.set(s.number());\n// Set\u003cnumber\u003e\n```\n\n#### Instances\n\n[Back to top][toc]\n\nYou can use `s.instance(Class)` to check that the input is an instance of a class. This is useful to validate inputs\nagainst classes:\n\n```typescript\nclass User {\n  public constructor(public name: string) {}\n}\n\nconst userInstanceValidation = s.instance(User);\nuserInstanceValidation.parse(new User('Sapphire')); // =\u003e User { name: 'Sapphire' }\nuserInstanceValidation.parse('oops'); // =\u003e throws ValidatorError\n```\n\n#### Records\n\n[Back to top][toc]\n\nRecord validations are similar to objects, but validate `Record\u003cstring, T\u003e` types. Keep in mind this does not check for\nthe keys, and cannot support validation for specific ones:\n\n```typescript\nconst tags = s.record(s.string());\n\ntags.parse({ foo: 'bar', hello: 'world' }); // =\u003e { foo: 'bar', hello: 'world' }\ntags.parse({ foo: 42 }); // =\u003e throws CombinedError\ntags.parse('Hello'); // =\u003e throws ValidateError\n```\n\n---\n\n\u003c!-- _**Function validation is not yet implemented and will be made available starting v2.1.0**_\n\n#### Functions // TODO\n\n[Back to top][toc]\n\nYou can define function validations. This checks for whether or not an input is a function:\n\n```typescript\ns.function(); // () =\u003e unknown\n```\n\nYou can define arguments by passing an array as the first argument, as well as the return type as the second:\n\n```typescript\ns.function([s.string()]); // (arg0: string) =\u003e unknown\ns.function([s.string(), s.number()], s.string()); // (arg0: string, arg1: number) =\u003e string\n```\n\n\u003e **Note**: Shapeshift will transform the given function into one with validation on arguments and output. You can\n\u003e access the `.raw` property of the function to get the unchecked function.\n\n--- --\u003e\n\n#### TypedArray\n\n[Back to top][toc]\n\n```ts\nconst typedArray = s.typedArray();\nconst int16Array = s.int16Array();\nconst uint16Array = s.uint16Array();\nconst uint8ClampedArray = s.uint8ClampedArray();\nconst int16Array = s.int16Array();\nconst uint16Array = s.uint16Array();\nconst int32Array = s.int32Array();\nconst uint32Array = s.uint32Array();\nconst float32Array = s.float32Array();\nconst float64Array = s.float64Array();\nconst bigInt64Array = s.bigInt64Array();\nconst bigUint64Array = s.bigUint64Array();\n```\n\nShapeshift includes a handful of validations specific to typed arrays.\n\n```typescript\ns.typedArray().lengthLessThan(5); // Length must be less than 5\ns.typedArray().lengthLessThanOrEqual(5); // Length must be 5 or less\ns.typedArray().lengthGreaterThan(5); // Length must be more than 5\ns.typedArray().lengthGreaterThanOrEqual(5); // Length must be 5 or more\ns.typedArray().lengthEqual(5); // Length must be exactly 5\ns.typedArray().lengthNotEqual(5); // Length must not be 5\ns.typedArray().lengthRange(0, 4); // Length L must satisfy 0 \u003c= L \u003c 4\ns.typedArray().lengthRangeInclusive(0, 4); // Length L must satisfy 0 \u003c= L \u003c= 4\ns.typedArray().lengthRangeExclusive(0, 4); // Length L must satisfy 0 \u003c L \u003c 4\n```\n\nNote that all of these methods have analogous methods for working with the typed array's byte length,\n`s.typedArray().byteLengthX()` - for instance, `s.typedArray().byteLengthLessThan(5)` is the same as\n`s.typedArray().lengthLessThan(5)` but for the array's byte length.\n\n---\n\n### Defining schemas (objects)\n\n[Back to top][toc]\n\n```typescript\n// Properties are required by default:\nconst animal = s.object({\n  name: s.string(),\n  age: s.number()\n});\n```\n\n#### Utility types for TypeScript\n\n[Back to top][toc]\n\nFor object validation Shapeshift exports 2 utility types that can be used to extract interfaces from schemas and define\nthe structure of a schema as an interface beforehand respectively.\n\n##### Extracting an interface from a schema\n\n[Back to top][toc]\n\nYou can use the `InferType` type to extract the interface from a schema, for example:\n\n```typescript\nimport { InferType, s } from '@sapphire/shapeshift';\n\nconst schema = s.object({\n  foo: s.string(),\n  bar: s.number(),\n  baz: s.boolean(),\n  qux: s.bigint(),\n  quux: s.date()\n});\n\ntype Inferredtype = InferType\u003ctypeof schema\u003e;\n\n// Expected type:\ntype Inferredtype = {\n  foo: string;\n  bar: number;\n  baz: boolean;\n  qux: bigint;\n  quux: Date;\n};\n```\n\n##### Defining the structure of a schema through an interface\n\n[Back to top][toc]\n\nYou can use the `SchemaOf` type to define the structure of a schema before defining the actual schema, for example:\n\n```typescript\nimport { s, SchemaOf } from '@sapphire/shapeshift';\n\ninterface IIngredient {\n  ingredientId: string | undefined;\n  name: string | undefined;\n}\n\ninterface IInstruction {\n  instructionId: string | undefined;\n  message: string | undefined;\n}\n\ninterface IRecipe {\n  recipeId: string | undefined;\n  title: string;\n  description: string;\n  instructions: IInstruction[];\n  ingredients: IIngredient[];\n}\n\ntype InstructionSchemaType = SchemaOf\u003cIInstruction\u003e;\n// Expected Type: ObjectValidator\u003cIInstruction\u003e\n\ntype IngredientSchemaType = SchemaOf\u003cIIngredient\u003e;\n// Expected Type: ObjectValidator\u003cIIngredient\u003e\n\ntype RecipeSchemaType = SchemaOf\u003cIRecipe\u003e;\n// Expected Type: ObjectValidator\u003cIRecipe\u003e\n\nconst instructionSchema: InstructionSchemaType = s.object({\n  instructionId: s.string().optional(),\n  message: s.string()\n});\n\nconst ingredientSchema: IngredientSchemaType = s.object({\n  ingredientId: s.string().optional(),\n  name: s.string()\n});\n\nconst recipeSchema: RecipeSchemaType = s.object({\n  recipeId: s.string().optional(),\n  title: s.string(),\n  description: s.string(),\n  instructions: s.array(instructionSchema),\n  ingredients: s.array(ingredientSchema)\n});\n```\n\n#### `.extend`:\n\n[Back to top][toc]\n\nYou can add additional fields using either an object or an ObjectValidator, in this case, you will get a new object\nvalidator with the merged properties:\n\n```typescript\nconst animal = s.object({\n  name: s.string().optional(),\n  age: s.number()\n});\n\nconst pet = animal.extend({\n  owner: s.string().nullish()\n});\n\nconst pet = animal.extend(\n  s.object({\n    owner: s.string().nullish()\n  })\n);\n```\n\n\u003e If both schemas share keys, an error will be thrown. Please use `.omit` on the first object if you desire this\n\u003e behaviour.\n\n#### `.pick` / `.omit`:\n\n[Back to top][toc]\n\nInspired by TypeScript's built-in `Pick` and `Omit` utility types, all object schemas have the aforementioned methods\nthat return a modifier version:\n\n```typescript\nconst pkg = s.object({\n  name: s.string(),\n  description: s.string(),\n  dependencies: s.string().array()\n});\n\nconst justTheName = pkg.pick(['name']);\n// s.object({ name: s.string() });\n\nconst noDependencies = pkg.omit(['dependencies']);\n// s.object({ name: s.string(), description: s.string() });\n```\n\n#### `.partial`\n\n[Back to top][toc]\n\nInspired by TypeScript's built-in `Partial` utility type, all object schemas have the aforementioned method that makes\nall properties optional:\n\n```typescript\nconst user = s.object({\n  username: s.string(),\n  password: s.string()\n}).partial;\n```\n\nWhich is the same as doing:\n\n```typescript\nconst user = s.object({\n  username: s.string().optional(),\n  password: s.string().optional()\n});\n```\n\n---\n\n#### `.required`\n\n[Back to top][toc]\n\nInspired by TypeScript's built-in `Required` utility type, all object schemas have the aforementioned method that makes\nall properties required:\n\n```typescript\nconst user = s.object({\n  username: s.string().optional(),\n  password: s.string().optional()\n}).required;\n```\n\nWhich is the same as doing:\n\n```typescript\nconst user = s.object({\n  username: s.string(),\n  password: s.string()\n});\n```\n\n---\n\n### Handling unrecognized keys\n\n[Back to top][toc]\n\nBy default, Shapeshift will not include keys that are not defined by the schema during parsing:\n\n```typescript\nconst person = s.object({\n  framework: s.string()\n});\n\nperson.parse({\n  framework: 'Sapphire',\n  awesome: true\n});\n// =\u003e { name: 'Sapphire' }\n```\n\n#### `.strict`\n\n[Back to top][toc]\n\nYou can disallow unknown keys with `.strict`. If the input includes any unknown keys, an error will be thrown.\n\n```typescript\nconst person = s.object({\n  framework: s.string()\n}).strict;\n\nperson.parse({\n  framework: 'Sapphire',\n  awesome: true\n});\n// =\u003e throws ValidationError\n```\n\n#### `.ignore`\n\n[Back to top][toc]\n\nYou can use the `.ignore` getter to reset an object schema to the default behaviour (ignoring unrecognized keys).\n\n#### `.passthrough`\n\n[Back to top][toc]\n\nYou can use the `.passthrough` getter to make the validator add the unrecognized properties the shape does not have,\nfrom the input.\n\n---\n\n### BaseValidator: methods and properties\n\n[Back to top][toc]\n\nAll validations in Shapeshift contain certain methods.\n\n- #### `.run(data: unknown): Result\u003cT, Error\u003e`: given a validation, you can call this method to check whether or not the\n\n  input is valid. If it is, a `Result` with `success: true` and a deep-cloned value will be returned with the given\n  constraints and transformations. Otherwise, a `Result` with `success: false` and an error is returned.\n\n- #### `.parse(data: unknown): T`: given a validations, you can call this method to check whether or not the input is valid.\n\n  If it is, a deep-cloned value will be returned with the given constraints and transformations. Otherwise, an error is\n  thrown.\n\n- #### `.transform\u003cR\u003e((value: T) =\u003e R): NopValidator\u003cR\u003e`: adds a constraint that modifies the input:\n\n```typescript\nimport { s } from '@sapphire/shapeshift';\n\nconst getLength = s.string().transform((value) =\u003e value.length);\ngetLength.parse('Hello There'); // =\u003e 11\n```\n\n\u003e :warning: `.transform`'s functions **must not throw**. If a validation error is desired to be thrown, `.reshape`\n\u003e instead.\n\n- #### `.reshape\u003cR\u003e((value: T) =\u003e Result\u003cR, Error\u003e | IConstraint): NopValidator\u003cR\u003e`: adds a constraint able to both validate\n  and modify the input:\n\n```typescript\nimport { s, Result } from '@sapphire/shapeshift';\n\nconst getLength = s.string().reshape((value) =\u003e Result.ok(value.length));\ngetLength.parse('Hello There'); // =\u003e 11\n```\n\n\u003e :warning: `.reshape`'s functions **must not throw**. If a validation error is desired to be thrown, use\n\u003e `Result.err(error)` instead.\n\n- #### `.default(value: T | (() =\u003e T))`: transform `undefined` into the given value or the callback's returned value:\n\n```typescript\nconst name = s.string().default('Sapphire');\nname.parse('Hello'); // =\u003e 'Hello'\nname.parse(undefined); // =\u003e 'Sapphire'\n```\n\n```typescript\nconst number = s.number().default(Math.random);\nnumber.parse(12); // =\u003e 12\nnumber.parse(undefined); // =\u003e 0.989911985608602\nnumber.parse(undefined); // =\u003e 0.3224350185068794\n```\n\n\u003e :warning: The default values are not validated.\n\n- #### `.optional`: a convenience method that returns a union of the type with `s.undefined()`.\n\n```typescript\ns.string().optional(); // s.union(s.string(), s.undefined())\n```\n\n- #### `.nullable`: a convenience method that returns a union of the type with `s.nullable()`.\n\n```typescript\ns.string().nullable(); // s.union(s.string(), s.nullable())\n```\n\n- #### `.nullish`: a convenience method that returns a union of the type with `s.nullish()`.\n\n```typescript\ns.string().nullish(); // s.union(s.string(), s.nullish())\n```\n\n- #### `.array`: a convenience method that returns an ArrayValidator with the type.\n\n```typescript\ns.string().array(); // s.array(s.string())\n```\n\n- #### `.or`: a convenience method that returns an UnionValidator with the type. This method is also overridden in\n  UnionValidator to just append one more entry.\n\n```typescript\ns.string().or(s.number());\n// =\u003e s.union(s.string(), s.number())\n\ns.object({ name: s.string() }).or(s.string(), s.number());\n// =\u003e s.union(s.object({ name: s.string() }), s.string(), s.number())\n```\n\n- #### `.when`: Adjust the schema based on a sibling or sinbling children fields.\n\nFor using when you provide an object literal where the key `is` is undefined, a value, or a matcher function; `then`\nprovides the schema when `is` resolves truthy, and `otherwise` provides the schema when `is` resolves falsey.\n\n##### Available options for providing `is`\n\nWhen `is` is not provided (`=== undefined`) it is strictly resolved as `Boolean(value)` wherein `value` is the current\nvalue of the referenced sibling. Note that if multiple siblings are referenced then all the values of the array need to\nresolve truthy for the `is` to resolve truthy.\n\nWhen `is` is a primitive literal it is strictly compared (`===`) to the current value.\n\nIf you want to use a different form of equality you can provide a function like: `is: (value) =\u003e value === true`.\n\n##### Resolving of the `key` (first) parameter\n\nFor resolving the `key` parameter to its respective value we use [lodash/get](https://lodash.com/docs#get). This means\nthat every way that Lodash supports resolving a key to its respective value is also supported by Shapeshift. This\nincludes:\n\n- Simply providing a string or number like `'name'` or `1`.\n- Providing a string or number with a dot notation like `'name.first'` (representative of a nested object structure of\n  `{ 'name': { 'first': 'Sapphire' } }` =\u003e resolves to `Sapphire`).\n- Providing a string or number with a bracket notation like `'name[0]'` (representative of an array structure of\n  `{ 'name': ['Sapphire', 'Framework'] }` =\u003e resolves to `Sapphire`).\n- Providing a string or number with a dot and bracket notation like `'name[1].first'` (representative of a nested object\n  structure of `{ 'name': [{ 'first': 'Sapphire' }, { 'first': 'Framework' }] }` =\u003e resolves to `Framework`).\n\n##### Examples\n\nLet's start with a basic example:\n\n```typescript\nconst whenPredicate = s.object({\n  booleanLike: s.boolean(),\n  numberLike: s.number().when('booleanLike', {\n    then: (schema) =\u003e schema.greaterThanOrEqual(5),\n    otherwise: (schema) =\u003e schema.lessThanOrEqual(5)\n  })\n});\n\nwhenPredicate.parse({ booleanLike: true, numberLike: 6 });\n// =\u003e { booleanLike: true, numberLike: 6 }\n\nwhenPredicate.parse({ booleanLike: true, numberLike: 4 });\n// =\u003e ExpectedConstraintError('s.number().greaterThanOrEqual', 'Invalid number value', 4, 'expected \u003e= 5')\n\nwhenPredicate.parse({ booleanLike: false, numberLike: 4 });\n// =\u003e { booleanLike: false, numberLike: 4 }\n```\n\nThe provided key can also be an array of sibling children:\n\n```typescript\nconst whenPredicate = s.object({\n  booleanLike: s.boolean(),\n  stringLike: s.string(),\n  numberLike: s.number().when(['booleanLike', 'stringLike'], {\n\tis: ([booleanLikeValue, stringLikeValue]) =\u003e booleanLikeValue === true \u0026\u0026 stringLikeValue === 'foobar',\n    then: (schema) =\u003e schema.greaterThanOrEqual(5),\n    otherwise: (schema) =\u003e schema.lessThanOrEqual(5)\n  })\n});\n\nwhenPredicate.parse({ booleanLike: true, stringLike: 'foobar', numberLike: 6 });\n// =\u003e { booleanLike: true, numberLike: 6 }\n\nwhenPredicate.parse({ booleanLike: true, stringLike: 'barfoo', numberLike: 4 });\n// =\u003e ExpectedConstraintError('s.number().greaterThanOrEqual', 'Invalid number value', 4, 'expected \u003e= 5')\n\nwhenPredicate.parse({ booleanLike: false, stringLike: 'foobar' numberLike: 4 });\n// =\u003e ExpectedConstraintError('s.number().greaterThanOrEqual', 'Invalid number value', 4, 'expected \u003e= 5')\n```\n\n### Enabling and disabling validation\n\n[Back to top][toc]\n\nAt times, you might want to have a consistent code base with validation, but would like to keep validation to the strict\nnecessities instead of the in-depth constraints available in shapeshift. By calling `setGlobalValidationEnabled` you can\ndisable validation at a global level, and by calling `setValidationEnabled` you can disable validation on a\nper-validator level.\n\n\u003e When setting the validation enabled status per-validator, you can also set it to `null` to use the global setting.\n\n```typescript\nimport { setGlobalValidationEnabled } from '@sapphire/shapeshift';\n\nsetGlobalValidationEnabled(false);\n```\n\n```typescript\nimport { s } from '@sapphire/shapeshift';\n\nconst predicate = s.string().lengthGreaterThan(5).setValidationEnabled(false);\n```\n\n## Buy us some doughnuts\n\n[Back to top][toc]\n\nSapphire Community is and always will be open source, even if we don't get donations. That being said, we know there are\namazing people who may still want to donate just to show their appreciation. Thank you very much in advance!\n\nWe accept donations through Open Collective, Ko-fi, Paypal, Patreon and GitHub Sponsorships. You can use the buttons\nbelow to donate through your method of choice.\n\n|   Donate With   |                       Address                       |\n| :-------------: | :-------------------------------------------------: |\n| Open Collective | [Click Here](https://sapphirejs.dev/opencollective) |\n|      Ko-fi      |      [Click Here](https://sapphirejs.dev/kofi)      |\n|     Patreon     |    [Click Here](https://sapphirejs.dev/patreon)     |\n|     PayPal      |     [Click Here](https://sapphirejs.dev/paypal)     |\n\n## Contributors\n\n[Back to top][toc]\n\nPlease make sure to read the [Contributing Guide][contributing] before making a pull request.\n\nThank you to all the people who already contributed to Sapphire!\n\n\u003ca href=\"https://github.com/sapphiredev/shapeshift/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contrib.rocks/image?repo=sapphiredev/shapeshift\" /\u003e\n\u003c/a\u003e\n\n[contributing]: https://github.com/sapphiredev/.github/blob/main/.github/CONTRIBUTING.md\n[`zod`]: https://github.com/colinhacks/zod\n[`yup`]: https://github.com/jquense/yup\n[documentation]: https://www.sapphirejs.dev/docs/Documentation/api-shapeshift/\n[toc]: #table-of-contents\n","funding_links":["https://github.com/sponsors/sapphiredev","https://patreon.com/sapphire_community","https://opencollective.com/sapphiredev","https://ko-fi.com/sapphirecommunity","https://sapphirejs.dev/paypal"],"categories":["hacktoberfest","TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsapphiredev%2Fshapeshift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsapphiredev%2Fshapeshift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsapphiredev%2Fshapeshift/lists"}