diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 6165e11e..1098ab4c 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -90,6 +90,13 @@ describe('VueTypes', () => { }) }) + describe('`.nullable`', () => { + it('should proxy the `nullable` validator', () => { + const expected = getExpectDescriptors(native.nullable()) + expect(getDescriptors(VueTypes.nullable)).toEqual(expected) + }) + }) + describe('`.custom`', () => { it('should proxy the `custom` validator', () => { const fn = () => true diff --git a/__tests__/shim.test.ts b/__tests__/shim.test.ts index f20a356d..7b146daa 100644 --- a/__tests__/shim.test.ts +++ b/__tests__/shim.test.ts @@ -311,6 +311,12 @@ describe('SHIM: VueTypes', () => { }) }) + describe('`.nullable`', () => { + it('should proxy the `nullable` validator', () => { + expect(VueTypes.nullable).toEqual({ type: null }) + }) + }) + describe('SHIM: `.custom`', () => { it('should exist', () => { expect(VueTypes.custom).toBeInstanceOf(Function) diff --git a/__tests__/validators/native.test.ts b/__tests__/validators/native.test.ts index cd941e23..b8134ff6 100644 --- a/__tests__/validators/native.test.ts +++ b/__tests__/validators/native.test.ts @@ -192,4 +192,14 @@ describe('Native validators', () => { } }) }) + + describe('nullable', () => { + it('should return a validator for null', () => { + expect(native.nullable().type).toBe(null) + }) + it('should not have any flag', () => { + expect((native.nullable() as any).isRequired).toBe(undefined) + expect((native.nullable() as any).def).toBe(undefined) + }) + }) }) diff --git a/docs/guide/namespaced.md b/docs/guide/namespaced.md index 7c08cac1..18be3d84 100644 --- a/docs/guide/namespaced.md +++ b/docs/guide/namespaced.md @@ -39,6 +39,7 @@ The main difference between namespaced native validators and those directly impo | integer | `0` | - | | symbol | - | - | | object | `{}` | yes | +| nullable | - | - | diff --git a/docs/guide/validators.md b/docs/guide/validators.md index 0f78a5e4..bc422fc0 100644 --- a/docs/guide/validators.md +++ b/docs/guide/validators.md @@ -274,6 +274,28 @@ props: { } ``` +### nullable + +Validates that a prop is null. + +```js +props: { + uniq: nullable() +} +``` + +::: warning +This validator **does not come with any flag or method**. It can be used with [`oneOfType`](#oneoftype) to make a **non required** prop nullable. + +```js +props: { + stringOrNull: oneOfType([string(), nullable()]) +} +``` + +**Use this validator sparingly.** Nullable props are not encouraged in Vue components, so please consider reviewing your strategy. +::: + ## Custom Validators Custom validators are a special kind of factory function useful to describe complex validation requirements. By design custom validators: diff --git a/examples/shared/validators.ts b/examples/shared/validators.ts index 085f4549..00772217 100644 --- a/examples/shared/validators.ts +++ b/examples/shared/validators.ts @@ -15,6 +15,7 @@ import { shape, toType, fromType, + nullable, } from 'vue-types' /** @@ -122,6 +123,8 @@ export const castedStringOrCastedObject = oneOfType([ object(), ]).def('one') +export const stringOrNull = oneOfType([string(), nullable()]).def('one') + /** * `arrayOf` validator examples */ diff --git a/examples/tsconfig.json b/examples/tsconfig.json index 21baa029..88e2bba9 100644 --- a/examples/tsconfig.json +++ b/examples/tsconfig.json @@ -16,5 +16,5 @@ "vue-types/*": ["../src/*"] } }, - "include": ["**/*.ts", "../src/**/*.ts"] + "include": ["**/*.ts", "**/*.vue", "../src/**/*.ts"] } diff --git a/examples/vue2/test-components/single.ts b/examples/vue2/test-components/single.ts index 0bdbb167..46d0758b 100644 --- a/examples/vue2/test-components/single.ts +++ b/examples/vue2/test-components/single.ts @@ -10,6 +10,7 @@ import { anyType, objectOfTuple, oneOfTuple, + stringOrNull, } from '../../shared/validators' const UserComponent = Vue.extend({ @@ -20,6 +21,7 @@ const UserComponent = Vue.extend({ hobbies: arrayOfStringsType, randomData: arrayOfMultipleType, score: scoreType, + maybeStr: stringOrNull, }, }) diff --git a/examples/vue3/test-components/single.ts b/examples/vue3/test-components/single.ts index 8fd07ef7..13a63bd0 100644 --- a/examples/vue3/test-components/single.ts +++ b/examples/vue3/test-components/single.ts @@ -11,6 +11,7 @@ import { anyType, objectOfTuple, oneOfTuple, + stringOrNull, } from '../../shared/validators' const UserComponent = defineComponent({ @@ -21,6 +22,7 @@ const UserComponent = defineComponent({ hobbies: arrayOfStringsType, randomData: arrayOfMultipleType, score: scoreType, + maybeStr: stringOrNull, }, }) diff --git a/examples/vue3/test-components/template.vue b/examples/vue3/test-components/template.vue index 3f37af5c..1e3c7af9 100644 --- a/examples/vue3/test-components/template.vue +++ b/examples/vue3/test-components/template.vue @@ -2,7 +2,8 @@
@@ -20,6 +21,7 @@ import { anyType, objectOfTuple, oneOfTuple, + stringOrNull, } from '../../shared/validators' export default defineComponent({ @@ -27,6 +29,7 @@ export default defineComponent({ user: userType, message: messageType, age: ageType, + maybeStr: stringOrNull, hobbies: arrayOfStringsType, randomData: arrayOfMultipleType, score: scoreType, diff --git a/src/index.ts b/src/index.ts index 90c14a53..bac27b3d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,6 +29,7 @@ import { integer, symbol, object, + nullable, } from './validators/native' import custom from './validators/custom' import oneOf from './validators/oneof' @@ -75,6 +76,10 @@ const BaseVueTypes = /*#__PURE__*/ (() => return symbol() } + static get nullable() { + return nullable() + } + static readonly custom = custom static readonly oneOf = oneOf static readonly instanceOf = instanceOf @@ -211,6 +216,7 @@ export { instanceOf, objectOf, shape, + nullable, createTypes, toType, toValidableType, diff --git a/src/shim.ts b/src/shim.ts index 20283b4a..6010bdaf 100644 --- a/src/shim.ts +++ b/src/shim.ts @@ -86,6 +86,9 @@ export const shape: TypeShim = (a: any) => return this }, }) +export const nullable: TypeShim = () => ({ + type: null, +}) /* eslint-enable @typescript-eslint/no-unused-vars */ function createValidator( @@ -153,6 +156,9 @@ const BaseVueTypes = /*#__PURE__*/ (() => static get integer() { return integer().def(this.defaults.integer) } + static get nullable() { + return nullable() + } static oneOf = oneOf static custom = custom static instanceOf = instanceOf diff --git a/src/validators/native.ts b/src/validators/native.ts index 4a14bc3b..73382cdb 100644 --- a/src/validators/native.ts +++ b/src/validators/native.ts @@ -47,3 +47,7 @@ export const symbol = () => return typeof value === 'symbol' }, }) + +export const nullable = () => ({ + type: null as unknown as PropType, +})