{"_id":"@alanrodas/shapeof","name":"@alanrodas/shapeof","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@alanrodas/shapeof","version":"0.1.0","description":"Find the shape of a JS/TS values easily.","repository":{"url":"git+https://github.com/alanrodas/shapeof.git"},"homepage":"https://alanrodas.github.io/shapeof","author":{"name":"Alan Rodas Bonjour","email":"alanrodas@gmail.com"},"license":"MIT","keywords":["Shapes","shapeof","hasShape","shapeLike","sameShape"],"main":"./dist/cjs/index.cjs","module":"./dist/esm/index.mjs","typings":"./dist/esm/typings/index.d.ts","exports":{".":{"import":{"types":"./dist/esm/typings/index.d.ts","default":"./dist/esm/index.mjs"},"require":{"types":"./dist/cjs/typings/index.d.ts","default":"./dist/cjs/index.cjs"}}},"typesVersions":{"*":{"*":["./dist/esm/typings/index.d.ts"]}},"packageManager":"npm@10.1.0","scripts":{"prepare":"is-ci || husky install","prepack":"npm start build","start":"nps -c ./package-scripts.cjs"},"devDependencies":{"@commitlint/cli":"^19.4.0","@commitlint/config-conventional":"^19.2.2","@eslint/compat":"^1.1.1","@eslint/eslintrc":"^3.1.0","@eslint/js":"^9.8.0","@jest/globals":"^29.7.0","@rollup/plugin-commonjs":"^26.0.1","@rollup/plugin-node-resolve":"^15.2.3","@rollup/plugin-typescript":"^11.1.6","husky":"^8.0.2","commitizen":"^4.3.0","concurrently":"^8.2.2","conventional-changelog-cli":"^5.0.0","cz-conventional-changelog":"^3.3.0","eslint":"9.8.0","eslint-config-prettier":"^9.1.0","eslint-plugin-import":"^2.29.1","eslint-plugin-no-null":"^1.0.2","eslint-plugin-prefer-arrow":"^1.2.3","eslint-plugin-prettier":"^5.2.1","is-ci":"^3.0.1","jest":"^29.7.0","nps":"^5.10.0","prettier":"^3.3.3","prettier-plugin-ini":"^1.2.0","prettier-plugin-sh":"^0.14.0","rimraf":"^6.0.1","rollup":"^4.20.0","rollup-plugin-copy":"^3.5.0","rollup-plugin-dts":"^6.1.1","rollup-plugin-execute":"^1.1.1","serve":"^14.2.3","ts-jest":"^29.2.4","tsx":"^4.17.0","typedoc":"^0.26.5","typescript":"^5.5.4","typescript-eslint":"^8.0.1"},"_id":"@alanrodas/shapeof@0.1.0","gitHead":"94cce2105e1441593e70c1f9eb0164baef4eb137","bugs":{"url":"https://github.com/alanrodas/shapeof/issues"},"_nodeVersion":"20.17.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-xV+gHtDe+GlnKtqXrxunVU+HpRG8qq07pOQhcmL22sssmbma59RGIR3INb/w/Hp60i6ntM98eaq9P39ezSZkTA==","shasum":"81a572d925ae27fd7c8a01ed2d1136415b97fcfb","tarball":"https://registry.npmjs.org/@alanrodas/shapeof/-/shapeof-0.1.0.tgz","fileCount":40,"unpackedSize":139298,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIELUMoc6xAvMGoqlXuqhhVv9m/8rLQ+QNpt8dF4HUeErAiA8oUNWY2846X8QXKjunC/l3xhCEA6lwxNhuVVlwtqZqg=="}]},"_npmUser":{"name":"alanrodas","email":"alanrodas@gmail.com"},"directories":{},"maintainers":[{"name":"alanrodas","email":"alanrodas@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/shapeof_0.1.0_1728580986550_0.7432506965453929"},"_hasShrinkwrap":false}},"time":{"created":"2024-10-10T17:23:06.437Z","0.1.0":"2024-10-10T17:23:06.801Z","modified":"2024-10-10T17:23:07.852Z"},"maintainers":[{"name":"alanrodas","email":"alanrodas@gmail.com"}],"description":"Find the shape of a JS/TS values easily.","homepage":"https://alanrodas.github.io/shapeof","keywords":["Shapes","shapeof","hasShape","shapeLike","sameShape"],"repository":{"url":"git+https://github.com/alanrodas/shapeof.git"},"author":{"name":"Alan Rodas Bonjour","email":"alanrodas@gmail.com"},"bugs":{"url":"https://github.com/alanrodas/shapeof/issues"},"license":"MIT","readme":"# shapeof\n\nFind the shape of a JS/TS values easily.\n\n[![Licence](https://img.shields.io/badge/AGPL--3.0_with_additional_terms-olivegreen?style=plastic&label=License&logo=open-source-initiative&logoColor=white&color=olivegreen)](https://github.com/alanrodas/shapeof/blob/main/LICENSE) [![Version](https://img.shields.io/github/package-json/v/alanrodas/shapeof?style=plastic&label=Version&logo=git-lfs&logoColor=white&color=crimson)](https://www.npmjs.com/package/@alanrodas/shapeof)\n\n[![API Docs](https://img.shields.io/github/package-json/homepage/alanrodas/shapeof?color=blue&label=API%20Docs&logo=gitbook&logoColor=white&style=plastic)](https://alanrodas.github.io/shapeof)\n\n![GitHub Workflow Tests](https://img.shields.io/github/actions/workflow/status/alanrodas/shapeof/on-commit-test.yml?style=plastic&label=Tests&logo=github-actions&logoColor=white) ![GitHub Workflow Build](https://img.shields.io/github/actions/workflow/status/alanrodas/shapeof/on-commit-build.yml?style=plastic&label=Build&logo=github-actions&logoColor=white)\n\n## Install and use\n\nInstall at your project by using **npm**.\n```sh\nnpm install shapeof\n```\n\nThen, just import the functions in your project, and start using them.\n```ts\nimport {shapeOf, hasShape} from 'shapeof';\n\nshapeOf(value);\nhasShape(value, shape);\n```\n\n## What is this?\n\nThis is a library for obtaining and checking the runtime **shape** of a a value in JavaScript and TypeScript.\n\nYou may think of **shapes** in a similar way as you will think of types, but the concept of **shape** extends the idea of runtime types that JS manages (and that you can obtain through `typeof`). Learn more about **shapes** below.\n\nThis module exports two main functions:\n* `shapeOf`: Returns the shape of the given value.\n* `hasShape`: answers a boolean stating if the given value has the given shape.\n\nNote that `hasShape` ensures a correct check of the **shape hierarchy** so it's more complex than just obtaining the shape with `shapeOf` and comparing, which may not be what you expect.\n\n>> You can read more about the usage of the functions in the next sections.\n\nThis library attempts to have small footprint on the code.\n\nAs an example, it may be used to check something such as:\n```ts\ntypeof receivedData === 'number' && Number.isInteger(receivedData)\n```\n\ninto something like:\n```ts\nshapeOf(receivedData) === 'int'\n```\nor even better:\n\n```ts\nhasShape(receivedData, 'int')\n```\n\nAlso, when checking complex object shapes:\n```ts\nobj && obj.a && typeof obj.a === 'string' && obj.b && typeof obj.b === 'number'\n```\n\nIt allows you to replace it with a more easily understandable code:\n```ts\nhasShape(obj, { a:'string', b: 'number'})\n```\n\n### When should I use it?\n\nThis library may be used to perform small checks on values, objects and arrays. It uniformly allows you to perform checks on common elements to check the runtime nature of the value.\n\nIt may be used to:\n* Validate arguments passed to a function, to ensure they are of the correct shape.\n* Validate the body or params of a request in a web service.\n* Validate objects returned by a library that is not uniform in what it returns.\n\nThe small footprint of the library and the fact that it handles common shapes such as `int` or `array` by default in an easy manner makes it quite useful in some scenarios where small checks need to be performed.\n\n### When not to use it?\n\nThis library attempts to have small footprint through the default configuration. Yet, more complex checks, may incur in big performance penalties.\n\nVerifying if an array has a complex inner shape, such as:\n```ts\nhasShape(array, ['int'])\n```\ninvolves traversing all the elements of the array, and verifying the type of each element, thus making it possibly slow for really long arrays.\n\nAlso verifying a complex object shape, involves traversing the properties of the object, in a recursive manner, thus involving a quite heavy footprint.\n\nAdditionally, note that this library does not support objects that may have circular references (and we are not planning to support them).\n\nIf you are worried about performance or have object that may have circular checks, you should not use this library.\n\nIf you are looking to perform more complex checks, such as if the value is a number in a range, or is a string that complies with an enum value, this library will not suffice either. Maybe you are looking for a JSON validator?\n\n## Shapes and shape hierarchy\n\nA **shape** is a categorization of a value based on the possible usage you are ought to perform on such a value, in the same sense of a type. We use the word **shape** instead of **type** as to not confuse the possible values involves with the ones built into JS.\n\nShapes may take different forms. A valid shape may be a string representing a \"base shape\", an array representing an \"array shape\" or an object representing an \"object shape\". Additionally, some strings and arrays may represent \"union shapes\".\n\nThe type definition in TypeScript for all shapes is defined as follows:\n```ts\ntype BaseShape = BaseShape | ArrayShape | ObjectShape | UnionShape;\n```\n\n### Base shapes\n\nThe **shapes** are a bigger categorization than types, and involve all the built-in types in JS as possible values. These are: **boolean**, **number**, **bigint**, **string**, **symbol**, **object**, **undefined** and **function**.\n\nBut we add a few more. For better support of numeric values we include the shapes\n**int**, **float**, **nan** and **infinity**. The **int** shape represents elements of the `number` type such as `3`, `Number(8)` and even `9.0`. The **infinity** shape is used for both positive and negative infinity, while **nan** is used only for the NaN value. The **float** value is used for all other numbers.\n\nBuilt-in objects that have special shapes and may be used commonly throughout your code also have specially assigned shapes: **null** (only the null value), **array** (any array), **regexp** (elements that are regular expressions, such as `/a/` or `RegExp('[a-z]'`)), **buffer** (instances created with `Buffer.from`) and **promise** (object created with promise or having a `then` property that is a function in the same shape as a promise).\n\nAnd finally, objects created out of a constructor other than the built in ones mentioned above will have the shape **instance**.\n\n> There is a special **wrapper** shape. We will discuss this shape later on.\n\nFinally, there is a shape by the name **any**. This is similar to the \"any type\" concept used in TypeScript. All objects have an \"any\" shape when asked, so they all unify with **any**.\n\nWe call all this shapes \"base shapes\". They are represented with strings of the aforementioned names.\n\nThe type definition in TypeScript for base shapes looks like the following:\n```ts\ntype BaseShape =\n    // built-in types\n    | 'boolean' | 'number' | 'bigint' | 'string' | 'symbol' | 'object' | 'undefined' | 'function'\n    // extended number shapes\n    | 'int' | 'float' | 'nan' | 'infinity'\n    // extended object shapes\n    | 'null' | 'array' | 'regexp' | 'buffer' | 'promise'\n    // other instances shape\n    | 'instance'\n    // the any shape\n    | 'any'\n    // the optional wrapper shape\n    | 'wrapper';\n```\n\nThese shapes are arranged in a hierarchy, as follows:\n```\nany\n |\n |- boolean\n |- bigint\n |- string\n |- symbol\n |- undefined\n |- number\n |    |\n |    |- int\n |    |- float\n |    |- nan\n |    |- infinity\n |\n |- object\n |    |\n |    |- null\n |    |- function\n |    |- array\n |    |- regexp\n |    |- buffer\n |    |- promise\n |    |- instance\n |    |- wrapper\n```\n\nThis particular hierarchy establishes a relationship of \"supershapes\" and \"subshapes\". These relationships will be used when unifying types or when attempting to check if an element matches a particular shape.\n\n* **When using `shapeOf`:**\nWhen using `shapeOf`, by default, you will be answered with the most specific base shape your element has. That is, if you ask for the shape of `8`, the shape `'int'` will be returned, and when asked for `/a/`, `'regexp'` will be returned.\n\n* **When using `hasShape`:**\nWhen using `hasShape`, when passed a base shape, you will be answered with `true` only if the shape of the object matches the given shape, or if the given shape is one of the \"supershapes\" of the object most specific shape. So for example, attempting to check if `7` is an `'int'` will return `true`, as well as attempting to check if it's a `'number'` or an `'any'`. For `{name: 'john'}`, it will return `true` when asked if its an `'object'` or an `'any'`.\n\nIn most cases, this shapes will suffice, but there are situations where you may need to know more about a particular shape, specially for shapes that are structured elements, such as arrays or objects. We provide support for working and specifying such shapes in two forms:\n\n### Array shapes\n\nAn \"array shape\" is a type of shape that state that the value is an array, but it also presents information about the internal elements of an array with one single element inside that in itself is a shape. So you can run queries like the following:\n```ts\nhasShape(value, ['int'])\n```\n\nThis will return `true` when value is not only an array, but all the internal elements of such array are integer values. You may use any shape in the internal element of the definition, so even arrays that have arrays inside may be represented as `[['regexp']]`.\n\n> Note that verifying or obtaining these shapes is a resource intensive process, so only use such shapes when it's really required.\n\nIf an empty array is passed as a shape, then it's considered the same as an array of `'any'` values. In itself, an array of `'any'` values is equivalent to using the base shape `array`, as any array will suffice.\n\n> Note that you may define arrays with more than one shape inside, but when used in that way, the array represents a union type, and not an array at all.\n\nThe type definition in TypeScript for base shapes looks like the following:\n```ts\ntype ArrayShape = Shape[];\n```\n\n* **When using `shapeOf`:**\nBy default, `shapeOf` will not return an array shape, but use `'array'` instead. This increases performance as the `shapeOf` function is actually just a few nested ifs. You may require to activate the behavior for obtaining this type of shapes instead of base ones by passing the `useFullObjectShapes` option as `true`. Note that activating this implies traversing the array fully, obtaining all object shapes, and then attempting to unify those shapes. This process is resource intensive, and becomes heavier the longest the array.\n\n* **When using `hasShape`:**\nWhen using `hasShape` using an array shape, two conditions should be met:\n    1. The value passed should be an array\n    2. The internal elements of the array should match the internal shape of the array shape.\nDifferently to `shapeOf`, no special option needs to be passed in order to obtain this behavior. But, as you may imagine, the second step is implies that the array needs to be traversed. So keep that in mind when checking for your shapes, and only use array shapes when really required.\n\n### Object shapes\n\nThe \"object shapes\" are a way of specifying the shape of an object, including the properties it has and the shapes of all those properties. An object that represents an object shape may look as follows:\n```ts\nconst objShape = {\n    worker_id: 'int',\n    name: 'string',\n    age: 'int',\n    addresses: [{\n        street: 'string',\n        number: 'int',\n        city: 'string'\n    }],\n}\n```\n\nAs you can see, the object shape defines a set of properties, on which, the values used are in itself shapes. These shapes may be base shapes, array shapes, or even other object shapes (and union shapes that we will see next).\n\n> Note that verifying or obtaining these shapes is a resource intensive process, so only use such shapes when it's really required.\n\nBy default, `shapeOf` will not return this shapes, but you may require to activate the behavior for obtaining this type of shapes instead of base ones.\n\nThe type definition in TypeScript for base shapes will look like the following if TS supported recursive types (the internal implementation is a little bit different, but with the same meaning):\n```ts\ntype ObjectShape = Record<string, Shape>;\n```\n\n\n* **When using `shapeOf`:**\nBy default, `shapeOf` will not return an object shape, but use `'object'` instead. This increases performance as the `shapeOf` function is actually just a few nested ifs. You may require to activate the behavior for obtaining this type of shapes instead of base ones by passing the `useFullObjectShapes` option as `true`. Note that activating this implies recursively obtaining the shape of every property of the object (which may include arrays or other objects as properties, involving additional steps). So, use the feature wisely.\n\n* **When using `hasShape`:**\nWhen using `hasShape` using an object shape, two conditions should be met:\n    1. The value passed should be a object that is not a built-in supported one.\n    2. The object should have AT LEAST every property declared in the shape, and the values of such properties should match the shape expected in the given object shape.\nDifferently to `shapeOf`, no special option needs to be passed in order to obtain this behavior. But, as you may imagine, the second step is implies that the object needs to be recursively checked.\nAs you may note, we say \"AT LEASE\" which involves that the object `{name: 'john', age: 35}` does have the shape `{name: 'string'}`. You may alter this behavior to perform an exact match, that is so that the object should have \"EXACTLY\" the shape given, with no less and no more properties. This is achieved by passing the `exactShape` option as `true` to the `hasShape` function.\n\n### Union shapes\n\nFor cases where a value may take more than one possible shape, you may use a \"union shape\". Union shapes can be written as string, if they are the union of base shapes, such as:\n```ts\n'number | bigint'\n```\n\n> Note that the space surrounding the pipe ( | ) is important, and should not be omitted.\n\nor as an array with more than one element, when they are the union of more complex shapes, such as:\n```ts\n[ {name: 'string', age: 'number'}, 'string' ]\n```\n\n* **When using `shapeOf`:**\n`shapeOf` will not attempt to identify union shapes, so it will never return one.\n\n* **When using `hasShape`:**\nWhen using `hasShape` using a union shape, the value is checked for any of the shapes used in the union. A value is considered to have the union shape if it has any of the shapes that conform the union.\n\n### Wrapper shape\n\nBoth function, `shapeOf` and `hasShape` accept an option by the name `unwrapBaseShapes**. This allows to change the way wrapper objects are treated.\nIf you don't have any idea what an object wrapper is, you should check [JavaScript data types and data structures at MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures).\n\nBasically, JS will use a primitive value for elements such as numbers or strings, but it will automatically convert the value to an object that wraps it when required, and unwrap it when not. That means that doing something like:\n```ts\n\"Hello\".includes('H')\n```\nwill involve this conversion internally, as sending the message `includes` to a primitive value is not possible, and an object is required.\n\nYou may obtain a wrapped object manually by using the object wrapper constructor with new:\n```ts\nnew String('hello')\n```\n\nBut do note that this is considered a bad practice. In most scenarios you will never need such a construction.\n\nSo by default, The `unwrapBaseShapes` is `true`, so we treat `new String('hello')` in the same way we treat `'hello'` or `String('hello')`.\n\nThis behavior can be altered, so object wrappers are distinguishable from the primitive values. If want this behavior you may set the option `unwrapBaseShapes` as `false`. In this scenario, the type returned will be `'wrapper'`.\n\nThe following types are checked for wrapped representations:\n\n| primitive shape   |  wrapped shape     |\n|-------------------|--------------------|\n| 'boolean'         | Boolean            |\n| 'number'\t        | Number             |\n| 'bigint'\t        | BigInt             |\n| 'string'\t        | String             |\n| 'symbol'\t        | Symbol             |\n\nWe recommend to avoid using the **wrapper** shape for most purposes.\n\n\n## Function usage\n\n### shapeOf\n\nThe signature of the function in TypeScript is as follows:\n```ts\nfunction shapeOf(value: any, options?: Partial<ShapeOfOptions>): Shape\n```\n\nwhere:\n```ts\ninterface ShapeOfOptions {\n    useFullObjectShapes: boolean;\n    unwrapBaseShapes: boolean;\n}\n```\n\nThe `value` parameter is expected to be the element from which to obtain the shape of. This value can be any JavaScript value, including `null` or `undefined`.\n\nThe `options` parameter is an object that can alter the behavior of the function. By default the values used are:\n```ts\n{\n    useFullObjectShapes: false,\n    unwrapBaseShapes: true\n}\n```\n\nIf you don't pass an object, those defaults will be used. If you pass a partial object, such as `{useFullObjectShapes: true}`, the missing properties will be treated with the default values, and the rest will have your assigned value.\n\nWe already discussed in **wrapper objects** section how `unwrapBaseShapes` alters the behavior, so you can access wrapper object distinctly from primitive values.\n\nThe option `useFullObjectShapes` determines if the return value will be limited to a **base shape** (when `false`), or if **array shapes** and **object shapes** (when `true`).\n\nHere are some example cases:\n```ts\nshapeOf(7)                         // 'int'\nshapeOf(9.23)                      // 'float'\nshapeOf('hello')                   // 'string'\nshapeOf(/hello/)                   // 'regexp'\nshapeOf(Buffer.from('hello'))      // 'buffer'\nshapeOf(new Promise(() => {}))     // 'promise'\nshapeOf([1, 7, 9])                 // 'array'\nshapeOf({name: 'john', age: 37})   // 'object'\nshapeOf(new Number(9.23))          // 'float'\nshapeOf(new String('hello'))       // 'string'\n\n// Enabling wrapper type\nshapeOf(new Number(9.23), {\n    unwrapBaseShapes: false        // 'wrapper'\n})\nshapeOf(new String('hello'), {\n    unwrapBaseShapes: false        // 'wrapper'\n})\n\n// Enabling full objects\nshapeOf([1, 7, 9], {\n    useFullObjectShapes: true      // '['int']'\n})\nshapeOf({name: 'john', age: 37}, {\n     useFullObjectShapes: true     // '{name: 'string', age: 'int'}'\n})\n```\n\n\n### hasShape\n\nThe signature of the function in TypeScript is as follows:\n```ts\nfunction hasShape(value: unknown, shape: Shape, options?: Partial<HasShapeOptions>): boolean\n```\n\nwhere:\n```ts\nconst defaultHasShapeOptions: HasShapeOptions = {\n    unwrapBaseShapes: true,\n    exactShape: false\n};\n```\n\nThe `value` parameter is expected to be the element from which to check the shape of. This value can be any JavaScript value, including `null` or `undefined`.\n\nThe `shape` parameter is the expected shape to check. It can be any shape, such as a base shape, an array shape, and object shape or a union shape.\n\nThe `options` parameter is an object that can alter the behavior of the function. By default the values used are:\n```ts\n{\n    unwrapBaseShapes: true,\n    exactShape: false\n}\n```\n\nIf you don't pass an object, those defaults will be used. If you pass a partial object, such as `{useFullObjectShapes: true}`, the missing properties will be treated with the default values, and the rest will have your assigned value.\n\nWe already discussed in **wrapper objects** section how `unwrapBaseShapes` alters the behavior, so you can access wrapper object distinctly from primitive values.\n\nThe option `exactShape` determines if the return value will check that an object passed as value should comply *AT LEAST* with the passed shape. If `false`, then when checking objects, the passed value may have more properties than the properties in the shape defined. If `true`, then when checking objects, the passed value needs to have exactly the same properties defined in the shape. For either case, the properties defined by the value are required to have the shapes defined by the property in the shape.\n\nAn important thing to note is that the shape is checked considering the hierarchy. So for example , if the value is `7` and the given shape is `number`, the result will be `true`, even though the actual shape of the value returned by shapeOf is `'int'`.\n\nHere are some example cases:\n```ts\n// The following are true\nhasShape(7, 'int')\nhasShape(7, 'number')\nhasShape(7, 'any')\nhasShape(9.23, 'float')\nhasShape(9.23, 'number')\nhasShape(9.23, 'any')\nhasShape('hello', 'string')\nhasShape('hello', 'any')\nhasShape(/hello/, 'regexp')\nhasShape(/hello/, 'object')\nhasShape(/hello/, 'any')\nhasShape(Buffer.from('hello'), 'buffer')\nhasShape(Buffer.from('hello'), 'object')\nhasShape(new Number(9.23), 'float')\nhasShape(new Number(9.23), 'number')\nhasShape(new Number(9.23), 'any')\nhasShape(new String('hello'), 'string')\nhasShape(new String('hello'), 'any')\nhasShape([1, 7, 9], 'array')\nhasShape([1, 7, 9], 'object')\nhasShape([1, 7, 9], 'any')\nhasShape({name: 'john', age: 37}, 'object')\nhasShape({name: 'john', age: 37}, 'any')\nhasShape(new Number(9.23), 'wrapper', {unwrapBaseShapes: false})\nhasShape(new Number(9.23), 'object', {unwrapBaseShapes: false})\nhasShape(new Number(9.23), 'any', {unwrapBaseShapes: false})\nhasShape(new String('hello'), 'wrapper', {unwrapBaseShapes: false})\nhasShape(new String('hello'), 'object', {unwrapBaseShapes: false})\nhasShape(new String('hello'), 'any', {unwrapBaseShapes: false})\nhasShape([1, 7, 9], ['int'])\nhasShape([1, 7, 9], ['any'])\nhasShape({name: 'john', age: 37}, {name: 'string', age: 'int'})\nhasShape({name: 'john', age: 37}, {name: 'string', age: 'number'})\nhasShape({name: 'john', age: 37}, {name: 'string', age: 'int'})\nhasShape({name: 'john', age: 37}, {name: 'string', age: 'number'})\nhasShape({name: 'john', age: 37}, {age: 'int'})\nhasShape({name: 'john', age: 37}, {name: 'string'})\nhasShape({name: 'john', age: 37}, {name: 'string', age: 'int'},\n    {exactShape: true})\nhasShape({name: 'john', age: 37}, {name: 'string', age: 'number'},\n    {exactShape: true})\n\n// The following are false\nhasShape(7, 'float')\nhasShape(9.23, 'int')\nhasShape('hello', 'symbol')\nhasShape(new Number(9.23), 'wrapper')\nhasShape(new String('hello'), 'wrapper')\nhasShape([1, 7, 9], ['bigint'])\nhasShape({name: 'john', age: 37}, {name: 'string', age: 'bigint'})\nhasShape({name: 'john', age: 37}, {age: 'int'},\n    {exactShape: true})\nhasShape({name: 'john', age: 37}, {name: 'string'},\n    {exactShape: true})\n```\n\n## Contributing\n\nIf you want to contribute to the project, please raise an issue to discuss the possible changes before including them, and send a pull request of your changes.\n","readmeFilename":"README.md"}