diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d4fd860..68d37ee 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -94,6 +94,7 @@ module.exports = { // eslint-plugin-unicorn 'unicorn/filename-case': 'off', + 'unicorn/no-null': 'off', 'unicorn/no-useless-undefined': 'off', // conflicts with consistent-return 'unicorn/prevent-abbreviations': ['warn', { replacements: { @@ -155,7 +156,6 @@ module.exports = { 'jest/require-top-level-describe': 'warn', // less strict other rules - 'unicorn/no-null': 'off', '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-unsafe-argument': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', diff --git a/README.md b/README.md index d53c443..a52b4ce 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,18 @@ Vue.component('MyComponent', { props: { disabled: booleanProp().withDefault(false), title: stringProp().optional, + description: stringProp().nullable, items: arrayProp().required, callback: functionProp<() => void>().optional, color: oneOfProp(['red', 'green', 'blue'] as const).withDefault('red'), }, mounted() { - this.disabled // type: boolean - this.title // type: string | undefined - this.items // type: string[] - this.callback // type: (() => void) | undefined - this.color // type: 'red' | 'green' | 'blue' + this.disabled // type: boolean + this.title // type: string | undefined + this.description // type: string | null + this.items // type: string[] + this.callback // type: (() => void) | undefined + this.color // type: 'red' | 'green' | 'blue' }, }); ``` @@ -41,6 +43,7 @@ npm install vue-ts-types Each of the prop functions returns an object with the following properties: * `.optional`: Use this to mark the prop as not required with a default value of `undefined`. Also includes `undefined` in the resulting prop type. +* `.nullable`: Use this to mark the prop as not required with a default value of `null`. Also includes `null` in the resulting prop type. * `.required`: Use this to mark the prop as required without a default value. * `.withDefault(value)`: Use this to set a default value for the prop. Note that the value has to fit the prop type. For non-primitive types, the value has to be a function that returns the default value. @@ -72,6 +75,8 @@ Type parameter `T` can be used to restrict the type at compile time with a union ```ts stringProp().optional // → prop type: string | undefined +stringProp().nullable + // → prop type: string | null stringProp().required // → prop type: string stringProp().withDefault('foo') @@ -81,6 +86,8 @@ type Foo = 'a' | 'b' | 'c'; stringProp().optional // → prop type: Foo | undefined +stringProp().nullable + // → prop type: Foo | null stringProp().required // → prop type: Foo stringProp().withDefault('a') @@ -94,6 +101,8 @@ Allows any boolean (validated at runtime and compile time). ```ts booleanProp().optional // → prop type: boolean | undefined +booleanProp().nullable + // → prop type: boolean | null booleanProp().required // → prop type: boolean booleanProp().withDefault(false) @@ -107,6 +116,8 @@ Allows any number (validated at runtime and compile time). ```ts numberProp().optional // → prop type: number | undefined +numberProp().nullable + // → prop type: number | null numberProp().required // → prop type: number numberProp().withDefault(3.1415) @@ -120,6 +131,8 @@ Allows any integer (validated at runtime). ```ts integerProp().optional // → prop type: number | undefined +integerProp().nullable + // → prop type: number | null integerProp().required // → prop type: number integerProp().withDefault(42) @@ -133,6 +146,8 @@ Allows any symbol (validated at runtime and compile time). ```ts symbolProp().optional // → prop type: symbol | undefined +symbolProp().nullable + // → prop type: symbol | null symbolProp().required // → prop type: symbol symbolProp().withDefault(Symbol('foo')) @@ -146,6 +161,8 @@ Allows any Vue component instance, name or options object. No built-in runtime v ```ts vueComponentProp().optional // → prop type: ComponentOptions | VueConstructor | string | undefined +vueComponentProp().nullable + // → prop type: ComponentOptions | VueConstructor | string | null vueComponentProp().required // → prop type: ComponentOptions | VueConstructor | string vueComponentProp().withDefault('close-icon') @@ -160,6 +177,8 @@ Type parameter `T` can be used to restrict the type at compile time. ```ts anyProp().optional // → prop type: any +anyProp().nullable + // → prop type: any anyProp().required // → prop type: any anyProp().withDefault('foo') @@ -167,6 +186,8 @@ anyProp().withDefault('foo') anyProp().optional // → prop type: string | undefined +anyProp().nullable + // → prop type: string | null anyProp().required // → prop type: string anyProp().withDefault('foo') @@ -181,6 +202,8 @@ Type parameter `T` can be used to restrict the type of the array items at compil ```ts arrayProp().optional // → prop type: unknown[] | undefined +arrayProp().nullable + // → prop type: unknown[] | null arrayProp().required // → prop type: unknown[] arrayProp().withDefault(() => []) @@ -188,6 +211,8 @@ arrayProp().withDefault(() => []) arrayProp().optional // → prop type: string[] | undefined +arrayProp().nullable + // → prop type: string[] | null arrayProp().required // → prop type: string[] arrayProp().withDefault(() => ['foo', 'bar']) @@ -202,6 +227,8 @@ Type parameter `T` can be used to restrict the type at compile time. ```ts objectProp().optional // → prop type: object | undefined +objectProp().nullable + // → prop type: object | null objectProp().required // → prop type: object objectProp().withDefault(() => ({})) @@ -213,6 +240,8 @@ interface User { objectProp().optional // → prop type: User | undefined +objectProp().nullable + // → prop type: User | null objectProp().required // → prop type: User objectProp().withDefault(() => ({ name: 'John' })) @@ -229,6 +258,8 @@ Type parameter `T` can be used to restrict the type to a specific function signa ```ts functionProp().optional // → prop type: Function | undefined +functionProp().nullable + // → prop type: Function | null functionProp().required // → prop type: Function @@ -236,6 +267,8 @@ type MyFunc = (a: number, b: string) => boolean; functionProp().optional // → prop type: MyFunc | undefined +functionProp().nullable + // → prop type: MyFunc | null functionProp().required // → prop type: MyFunc ``` @@ -250,6 +283,8 @@ Type parameter `T` can be used to adjust the inferred type at compile time, this ```ts oneOfProp(['foo', 'bar'] as const).optional // → prop type: 'foo' | 'bar' | undefined +oneOfProp(['foo', 'bar'] as const).nullable + // → prop type: 'foo' | 'bar' | null oneOfProp(['foo', 'bar'] as const).required // → prop type: 'foo' | 'bar' oneOfProp(['foo', 'bar'] as const).withDefault('foo') @@ -264,6 +299,8 @@ Type parameter `T` can be used to adjust the inferred type at compile time, this ```ts oneOfObjectKeysProp({ foo: 1, bar: 2 }).optional // → prop type: 'foo' | 'bar' | undefined +oneOfObjectKeysProp({ foo: 1, bar: 2 }).nullable + // → prop type: 'foo' | 'bar' | null oneOfObjectKeysProp({ foo: 1, bar: 2 }).required // → prop type: 'foo' | 'bar' oneOfObjectKeysProp({ foo: 1, bar: 2 }).withDefault('foo') @@ -278,6 +315,8 @@ Type parameter `T` has to be used to adjust the type at compile time. ```ts oneOfTypesProp([Number, String]).optional // → prop type: string | number | undefined +oneOfTypesProp([Number, String]).nullable + // → prop type: string | number | null oneOfTypesProp([Number, String]).required // → prop type: string | number oneOfTypesProp([Number, String]).withDefault(42) @@ -292,6 +331,8 @@ Type parameter `T` can be used to adjust the inferred type at compile time. ```ts instanceOfProp(Date).optional // → prop type: Date | undefined +instanceOfProp(Date).nullable + // → prop type: Date | null instanceOfProp(Date).required // → prop type: Date instanceOfProp(Date).withDefault(() => new Date()) diff --git a/src/prop-types/function.ts b/src/prop-types/function.ts index b9fa81b..ac3619c 100644 --- a/src/prop-types/function.ts +++ b/src/prop-types/function.ts @@ -4,6 +4,7 @@ import { vuePropValidator } from '../validators'; interface FunctionPropOptionsGenerator { optional: DefaultPropOptions & { default?: () => T }; + nullable: DefaultPropOptions & { default?: (() => T) | null }; required: RequiredPropOptions & { default?: () => T }; } @@ -23,6 +24,12 @@ export const functionProp = (validator?: Validator): Functio default: undefined, validator: vuePropValidator(validator), }, + nullable: { + type: Function as unknown as () => T, + required: false, + default: null, + validator: vuePropValidator(validator), + }, required: { type: Function as unknown as () => T, required: true, diff --git a/src/types.ts b/src/types.ts index 4aa6497..a2c84b0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,6 +19,7 @@ export type DefaultPropOptions = PropOptions & { default: unknown } export interface PropOptionsGenerator { optional: DefaultPropOptions; + nullable: DefaultPropOptions; withDefault: (defaultValue: OneOfDefaultType) => DefaultPropOptions; required: RequiredPropOptions; } diff --git a/src/util.ts b/src/util.ts index f361c40..c90efe2 100644 --- a/src/util.ts +++ b/src/util.ts @@ -9,6 +9,12 @@ export const propOptionsGenerator = (type?: PropType, userValidator?: Vali default: undefined, validator: vuePropValidator(userValidator, ...typeValidators), }, + nullable: { + type, + required: false, + default: null, + validator: vuePropValidator(userValidator, ...typeValidators), + }, withDefault: (defaultValue: OneOfDefaultType): DefaultPropOptions => ({ type, required: false, diff --git a/tests/prop-types/any.spec.ts b/tests/prop-types/any.spec.ts index 215ba04..b9843e1 100644 --- a/tests/prop-types/any.spec.ts +++ b/tests/prop-types/any.spec.ts @@ -11,6 +11,17 @@ describe('anyProp().optional', () => { }); }); +describe('anyProp().nullable', () => { + it('creates the correct prop options', () => { + expect(anyProp().nullable).toStrictEqual({ + type: undefined, + required: false, + default: null, + validator: undefined, + }); + }); +}); + describe('anyProp().withDefault', () => { it('creates the correct prop options', () => { expect(anyProp().withDefault('foo')).toStrictEqual({ diff --git a/tests/prop-types/array.spec.ts b/tests/prop-types/array.spec.ts index d03eef5..b434631 100644 --- a/tests/prop-types/array.spec.ts +++ b/tests/prop-types/array.spec.ts @@ -11,6 +11,17 @@ describe('arrayProp().optional', () => { }); }); +describe('arrayProp().nullable', () => { + it('creates the correct prop options', () => { + expect(arrayProp().nullable).toStrictEqual({ + type: Array, + required: false, + default: null, + validator: undefined, + }); + }); +}); + const defaultGenerator = () => ['foo']; describe('arrayProp().withDefault', () => { diff --git a/tests/prop-types/boolean.spec.ts b/tests/prop-types/boolean.spec.ts index e0efb75..093d671 100644 --- a/tests/prop-types/boolean.spec.ts +++ b/tests/prop-types/boolean.spec.ts @@ -11,6 +11,17 @@ describe('booleanProp().optional', () => { }); }); +describe('booleanProp().nullable', () => { + it('creates the correct prop options', () => { + expect(booleanProp().nullable).toStrictEqual({ + type: Boolean, + required: false, + default: null, + validator: undefined, + }); + }); +}); + describe('booleanProp().withDefault', () => { it('creates the correct prop options', () => { expect(booleanProp().withDefault(false)).toStrictEqual({ diff --git a/tests/prop-types/function.spec.ts b/tests/prop-types/function.spec.ts index b30d7db..449a68d 100644 --- a/tests/prop-types/function.spec.ts +++ b/tests/prop-types/function.spec.ts @@ -11,6 +11,17 @@ describe('functionProp().optional', () => { }); }); +describe('functionProp().nullable', () => { + it('creates the correct prop options', () => { + expect(functionProp().nullable).toStrictEqual({ + type: Function, + required: false, + default: null, + validator: undefined, + }); + }); +}); + describe('functionProp().required', () => { it('creates the correct prop options', () => { expect(functionProp().required).toStrictEqual({ diff --git a/tests/prop-types/instanceOf.spec.ts b/tests/prop-types/instanceOf.spec.ts index c9f397b..8f869f9 100644 --- a/tests/prop-types/instanceOf.spec.ts +++ b/tests/prop-types/instanceOf.spec.ts @@ -13,6 +13,17 @@ describe('instanceOfProp().optional', () => { }); }); +describe('instanceOfProp().nullable', () => { + it('creates the correct prop options', () => { + expect(instanceOfProp(User).nullable).toStrictEqual({ + type: User, + required: false, + default: null, + validator: expect.any(Function), + }); + }); +}); + describe('instanceOfProp().withDefault', () => { it('creates the correct prop options', () => { expect(instanceOfProp(User).withDefault(() => new User())).toStrictEqual({ diff --git a/tests/prop-types/integer.spec.ts b/tests/prop-types/integer.spec.ts index 0c98909..8ff7f7e 100644 --- a/tests/prop-types/integer.spec.ts +++ b/tests/prop-types/integer.spec.ts @@ -11,6 +11,17 @@ describe('integerProp().optional', () => { }); }); +describe('integerProp().nullable', () => { + it('creates the correct prop options', () => { + expect(integerProp().nullable).toStrictEqual({ + type: Number, + required: false, + default: null, + validator: expect.any(Function), + }); + }); +}); + describe('integerProp().withDefault', () => { it('creates the correct prop options', () => { expect(integerProp().withDefault(27)).toStrictEqual({ diff --git a/tests/prop-types/number.spec.ts b/tests/prop-types/number.spec.ts index f426924..4ef09dd 100644 --- a/tests/prop-types/number.spec.ts +++ b/tests/prop-types/number.spec.ts @@ -11,6 +11,17 @@ describe('numberProp().optional', () => { }); }); +describe('numberProp().nullable', () => { + it('creates the correct prop options', () => { + expect(numberProp().nullable).toStrictEqual({ + type: Number, + required: false, + default: null, + validator: undefined, + }); + }); +}); + describe('numberProp().withDefault', () => { it('creates the correct prop options', () => { expect(numberProp().withDefault(27)).toStrictEqual({ diff --git a/tests/prop-types/object.spec.ts b/tests/prop-types/object.spec.ts index cad5a3d..8663d42 100644 --- a/tests/prop-types/object.spec.ts +++ b/tests/prop-types/object.spec.ts @@ -11,6 +11,17 @@ describe('objectProp().optional', () => { }); }); +describe('objectProp().nullable', () => { + it('creates the correct prop options', () => { + expect(objectProp().nullable).toStrictEqual({ + type: Object, + required: false, + default: null, + validator: undefined, + }); + }); +}); + const defaultGenerator = () => ({ foo: 'bar' }); describe('objectProp().withDefault', () => { diff --git a/tests/prop-types/oneOf.spec.ts b/tests/prop-types/oneOf.spec.ts index ac73458..a9c586a 100644 --- a/tests/prop-types/oneOf.spec.ts +++ b/tests/prop-types/oneOf.spec.ts @@ -20,6 +20,26 @@ describe('oneOfProp().optional', () => { }); }); +describe('oneOfProp().nullable', () => { + it('creates the correct prop options', () => { + expect(oneOfProp(['a', 'b', 'c'] as const).nullable).toStrictEqual({ + type: String, + required: false, + default: null, + validator: expect.any(Function), + }); + }); + + it('has the correct type', () => { + expect(oneOfProp(['a', 'b', 'c'] as const).nullable.type).toStrictEqual(String); + expect(oneOfProp([1, 2, 3] as const).nullable.type).toStrictEqual(Number); + expect(oneOfProp(['foo', 1, 2, 3] as const).nullable.type).toStrictEqual([String, Number]); + expect(oneOfProp([true, false, 'both'] as const).nullable.type).toStrictEqual([Boolean, String]); + expect(oneOfProp([undefined, null] as const).nullable.type).toStrictEqual(undefined); + expect(oneOfProp([undefined, 'defined'] as const).nullable.type).toStrictEqual(String); + }); +}); + describe('oneOfProp().withDefault', () => { it('creates the correct prop options', () => { expect(oneOfProp(['a', 'b', 'c'] as const).withDefault('a')).toStrictEqual({ diff --git a/tests/prop-types/oneOfObjectKeys.spec.ts b/tests/prop-types/oneOfObjectKeys.spec.ts index 5d0df76..bd0807d 100644 --- a/tests/prop-types/oneOfObjectKeys.spec.ts +++ b/tests/prop-types/oneOfObjectKeys.spec.ts @@ -13,6 +13,17 @@ describe('oneOfObjectKeysProp().optional', () => { }); }); +describe('oneOfObjectKeysProp().nullable', () => { + it('creates the correct prop options', () => { + expect(oneOfObjectKeysProp(options).nullable).toStrictEqual({ + type: String, + required: false, + default: null, + validator: expect.any(Function), + }); + }); +}); + describe('oneOfObjectKeysProp().withDefault', () => { it('creates the correct prop options', () => { expect(oneOfObjectKeysProp(options).withDefault('a')).toStrictEqual({ diff --git a/tests/prop-types/oneOfTypes.spec.ts b/tests/prop-types/oneOfTypes.spec.ts index 3b02a9d..5892529 100644 --- a/tests/prop-types/oneOfTypes.spec.ts +++ b/tests/prop-types/oneOfTypes.spec.ts @@ -11,6 +11,17 @@ describe('oneOfTypesProp().optional', () => { }); }); +describe('oneOfTypesProp().nullable', () => { + it('creates the correct prop options', () => { + expect(oneOfTypesProp([Number, String]).nullable).toStrictEqual({ + type: [Number, String], + required: false, + default: null, + validator: undefined, + }); + }); +}); + describe('oneOfTypesProp().withDefault', () => { it('creates the correct prop options', () => { expect(oneOfTypesProp([Number, String]).withDefault('a')).toStrictEqual({ diff --git a/tests/prop-types/string.spec.ts b/tests/prop-types/string.spec.ts index 9d859bb..fae9221 100644 --- a/tests/prop-types/string.spec.ts +++ b/tests/prop-types/string.spec.ts @@ -11,6 +11,17 @@ describe('stringProp().optional', () => { }); }); +describe('stringProp().nullable', () => { + it('creates the correct prop options', () => { + expect(stringProp().nullable).toStrictEqual({ + type: String, + required: false, + default: null, + validator: undefined, + }); + }); +}); + describe('stringProp().withDefault', () => { it('creates the correct prop options', () => { expect(stringProp().withDefault('foo')).toStrictEqual({ diff --git a/tests/prop-types/symbol.spec.ts b/tests/prop-types/symbol.spec.ts index c107a5a..568bbc8 100644 --- a/tests/prop-types/symbol.spec.ts +++ b/tests/prop-types/symbol.spec.ts @@ -11,6 +11,17 @@ describe('symbolProp().optional', () => { }); }); +describe('symbolProp().nullable', () => { + it('creates the correct prop options', () => { + expect(symbolProp().nullable).toStrictEqual({ + type: undefined, + required: false, + default: null, + validator: expect.any(Function), + }); + }); +}); + describe('symbolProp().withDefault', () => { it('creates the correct prop options', () => { expect(symbolProp().withDefault(Symbol.for('foo'))).toStrictEqual({ diff --git a/tests/prop-types/vueComponent.spec.ts b/tests/prop-types/vueComponent.spec.ts index 588df15..b7c6da3 100644 --- a/tests/prop-types/vueComponent.spec.ts +++ b/tests/prop-types/vueComponent.spec.ts @@ -11,6 +11,17 @@ describe('vueComponentProp().optional', () => { }); }); +describe('vueComponentProp().nullable', () => { + it('creates the correct prop options', () => { + expect(vueComponentProp().nullable).toStrictEqual({ + type: [Object, String], + required: false, + default: null, + validator: undefined, + }); + }); +}); + describe('vueComponentProp().withDefault', () => { it('creates the correct prop options', () => { expect(vueComponentProp().withDefault('foo')).toStrictEqual({ diff --git a/type-tests/prop-types/any.type.spec.ts b/type-tests/prop-types/any.type.spec.ts index bee04e2..80e2acb 100644 --- a/type-tests/prop-types/any.type.spec.ts +++ b/type-tests/prop-types/any.type.spec.ts @@ -40,6 +40,40 @@ describe('anyProp().optional', () => { }); }); +describe('anyProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectNotAssignable>(anyProp().nullable); + + expectType>( + createVue2Component(anyProp().nullable), + ); + + expectType>( + createVue2Component(anyProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectNotAssignable>(anyProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectAssignable>(anyProp().nullable); + expectNotAssignable>(anyProp().nullable); + }); +}); + describe('anyProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable(anyProp().withDefault('foo')); diff --git a/type-tests/prop-types/array.type.spec.ts b/type-tests/prop-types/array.type.spec.ts index 62954be..2ce017c 100644 --- a/type-tests/prop-types/array.type.spec.ts +++ b/type-tests/prop-types/array.type.spec.ts @@ -37,6 +37,37 @@ describe('arrayProp().optional', () => { }); }); +describe('arrayProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(arrayProp().nullable); + expectAssignable>(arrayProp().nullable); + expectNotAssignable>(arrayProp().nullable); + expectNotAssignable>(arrayProp().nullable); + + expectType>( + createVue2Component(arrayProp().nullable), + ); + + expectType>( + createVue2Component(arrayProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(arrayProp().nullable); + expectAssignable>(arrayProp().nullable); + expectNotAssignable>(arrayProp().nullable); + expectNotAssignable>(arrayProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(arrayProp().nullable); + expectAssignable>(arrayProp().nullable); + expectNotAssignable>(arrayProp().nullable); + expectNotAssignable>(arrayProp().nullable); + }); +}); + describe('arrayProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(arrayProp().withDefault(() => ['foo', 'bar'])); diff --git a/type-tests/prop-types/boolean.type.spec.ts b/type-tests/prop-types/boolean.type.spec.ts index 74782df..370b5a8 100644 --- a/type-tests/prop-types/boolean.type.spec.ts +++ b/type-tests/prop-types/boolean.type.spec.ts @@ -27,6 +27,27 @@ describe('booleanProp().optional', () => { }); }); +describe('booleanProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(booleanProp().nullable); + expectNotAssignable>(booleanProp().nullable); + + expectType>( + createVue2Component(booleanProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(booleanProp().nullable); + expectNotAssignable>(booleanProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(booleanProp().nullable); + expectNotAssignable>(booleanProp().nullable); + }); +}); + describe('booleanProp().withDefault(false)', () => { describe('Vue 2.6', () => { expectAssignable>(booleanProp().withDefault(false)); diff --git a/type-tests/prop-types/function.type.spec.ts b/type-tests/prop-types/function.type.spec.ts index e6bf8ed..ea0553a 100644 --- a/type-tests/prop-types/function.type.spec.ts +++ b/type-tests/prop-types/function.type.spec.ts @@ -41,6 +41,37 @@ describe('functionProp().optional', () => { }); }); +describe('functionProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(functionProp().nullable); + expectAssignable>(functionProp().nullable); + expectNotAssignable>(functionProp().nullable); + expectNotAssignable>(functionProp().nullable); + + expectType>( + createVue2Component(functionProp().nullable), + ); + + expectType>( + createVue2Component(functionProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(functionProp().nullable); + expectAssignable>(functionProp().nullable); + expectNotAssignable>(functionProp().nullable); + expectNotAssignable>(functionProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(functionProp().nullable); + expectAssignable>(functionProp().nullable); + expectNotAssignable>(functionProp().nullable); + expectNotAssignable>(functionProp().nullable); + }); +}); + describe('functionProp().required', () => { describe('Vue 2.6', () => { expectAssignable>(functionProp().required); diff --git a/type-tests/prop-types/instanceOf.type.spec.ts b/type-tests/prop-types/instanceOf.type.spec.ts index 5a4a9fd..dfd69cc 100644 --- a/type-tests/prop-types/instanceOf.type.spec.ts +++ b/type-tests/prop-types/instanceOf.type.spec.ts @@ -34,6 +34,27 @@ describe('instanceOfProp().optional', () => { }); }); +describe('instanceOfProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(instanceOfProp(User).optional); + expectNotAssignable>(instanceOfProp(User).optional); + + expectType>( + createVue2Component(instanceOfProp(User).optional), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(instanceOfProp(User).optional); + expectNotAssignable>(instanceOfProp(User).optional); + }); + + describe('Vue 3', () => { + expectAssignable>(instanceOfProp(User).optional); + expectNotAssignable>(instanceOfProp(User).optional); + }); +}); + describe('instanceOfProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(instanceOfProp(User).withDefault(() => new User())); diff --git a/type-tests/prop-types/integer.type.spec.ts b/type-tests/prop-types/integer.type.spec.ts index 9c64414..31fd8fd 100644 --- a/type-tests/prop-types/integer.type.spec.ts +++ b/type-tests/prop-types/integer.type.spec.ts @@ -27,6 +27,27 @@ describe('integerProp().optional', () => { }); }); +describe('integerProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(integerProp().nullable); + expectNotAssignable>(integerProp().nullable); + + expectType>( + createVue2Component(integerProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(integerProp().nullable); + expectNotAssignable>(integerProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(integerProp().nullable); + expectNotAssignable>(integerProp().nullable); + }); +}); + describe('integerProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(integerProp().withDefault(27)); diff --git a/type-tests/prop-types/number.type.spec.ts b/type-tests/prop-types/number.type.spec.ts index b70679d..3ae2634 100644 --- a/type-tests/prop-types/number.type.spec.ts +++ b/type-tests/prop-types/number.type.spec.ts @@ -27,6 +27,27 @@ describe('numberProp().optional', () => { }); }); +describe('numberProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(numberProp().nullable); + expectNotAssignable>(numberProp().nullable); + + expectType>( + createVue2Component(numberProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(numberProp().nullable); + expectNotAssignable>(numberProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(numberProp().nullable); + expectNotAssignable>(numberProp().nullable); + }); +}); + describe('numberProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(numberProp().withDefault(27)); diff --git a/type-tests/prop-types/object.type.spec.ts b/type-tests/prop-types/object.type.spec.ts index 2b0ca0e..da5d58c 100644 --- a/type-tests/prop-types/object.type.spec.ts +++ b/type-tests/prop-types/object.type.spec.ts @@ -38,6 +38,34 @@ describe('objectProp().optional', () => { }); }); +describe('objectProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(objectProp().nullable); + expectAssignable>(objectProp().nullable); + expectNotAssignable>(objectProp().nullable); + + expectType>( + createVue2Component(objectProp().nullable), + ); + + expectType>( + createVue2Component(objectProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(objectProp().nullable); + expectAssignable>(objectProp().nullable); + expectNotAssignable>(objectProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(objectProp().nullable); + expectAssignable>(objectProp().nullable); + expectNotAssignable>(objectProp().nullable); + }); +}); + const userGenerator = () => ({ name: 'bar' }); describe('objectProp().withDefault', () => { diff --git a/type-tests/prop-types/oneOf.type.spec.ts b/type-tests/prop-types/oneOf.type.spec.ts index f54f5f0..d2cf05e 100644 --- a/type-tests/prop-types/oneOf.type.spec.ts +++ b/type-tests/prop-types/oneOf.type.spec.ts @@ -30,6 +30,27 @@ describe('oneOfProp().optional', () => { }); }); +describe('oneOfProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(oneOfProp(['a', 'b', 'c']).nullable); + expectAssignable>(oneOfProp(options).nullable); + + expectType>( + createVue2Component(oneOfProp(options).nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(oneOfProp(['a', 'b', 'c']).nullable); + expectAssignable>(oneOfProp(options).nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(oneOfProp(['a', 'b', 'c']).nullable); + expectAssignable>(oneOfProp(options).nullable); + }); +}); + describe('oneOfProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(oneOfProp(options).withDefault('a')); diff --git a/type-tests/prop-types/oneOfObjectKeys.type.spec.ts b/type-tests/prop-types/oneOfObjectKeys.type.spec.ts index 23ce29c..8effa31 100644 --- a/type-tests/prop-types/oneOfObjectKeys.type.spec.ts +++ b/type-tests/prop-types/oneOfObjectKeys.type.spec.ts @@ -27,6 +27,24 @@ describe('oneOfObjectKeysProp().optional', () => { }); }); +describe('oneOfObjectKeysProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(oneOfObjectKeysProp(options).nullable); + + expectType>( + createVue2Component(oneOfObjectKeysProp(options).nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(oneOfObjectKeysProp(options).nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(oneOfObjectKeysProp(options).nullable); + }); +}); + describe('oneOfObjectKeysProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(oneOfObjectKeysProp(options).withDefault('a')); diff --git a/type-tests/prop-types/oneOfTypes.type.spec.ts b/type-tests/prop-types/oneOfTypes.type.spec.ts index 8c5bb1a..afe3602 100644 --- a/type-tests/prop-types/oneOfTypes.type.spec.ts +++ b/type-tests/prop-types/oneOfTypes.type.spec.ts @@ -27,6 +27,24 @@ describe('oneOfTypesProp().optional', () => { }); }); +describe('oneOfTypesProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(oneOfTypesProp(options).nullable); + + expectType>( + createVue2Component(oneOfTypesProp(options).nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(oneOfTypesProp(options).nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(oneOfTypesProp(options).nullable); + }); +}); + describe('oneOfTypesProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(oneOfTypesProp(options).withDefault('a')); diff --git a/type-tests/prop-types/string.type.spec.ts b/type-tests/prop-types/string.type.spec.ts index ecb4fe5..0d7d355 100644 --- a/type-tests/prop-types/string.type.spec.ts +++ b/type-tests/prop-types/string.type.spec.ts @@ -39,6 +39,37 @@ describe('stringProp().optional', () => { }); }); +describe('stringProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(stringProp().nullable); + expectAssignable>(stringProp().nullable); + expectNotAssignable>(stringProp().nullable); + expectNotAssignable>(stringProp().nullable); + + expectType>( + createVue2Component(stringProp().nullable), + ); + + expectType>( + createVue2Component(stringProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(stringProp().nullable); + expectAssignable>(stringProp().nullable); + expectNotAssignable>(stringProp().nullable); + expectNotAssignable>(stringProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(stringProp().nullable); + expectAssignable>(stringProp().nullable); + expectNotAssignable>(stringProp().nullable); + expectNotAssignable>(stringProp().nullable); + }); +}); + describe('stringProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(stringProp().withDefault('foo')); diff --git a/type-tests/prop-types/symbol.type.spec.ts b/type-tests/prop-types/symbol.type.spec.ts index 4837dc9..b4591f3 100644 --- a/type-tests/prop-types/symbol.type.spec.ts +++ b/type-tests/prop-types/symbol.type.spec.ts @@ -27,6 +27,27 @@ describe('symbolProp().optional', () => { }); }); +describe('symbolProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(symbolProp().nullable); + expectNotAssignable>(symbolProp().nullable); + + expectType>( + createVue2Component(symbolProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(symbolProp().nullable); + expectNotAssignable>(symbolProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(symbolProp().nullable); + expectNotAssignable>(symbolProp().nullable); + }); +}); + describe('symbolProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(symbolProp().withDefault(Symbol.for('foo'))); diff --git a/type-tests/prop-types/vueComponent.type.spec.ts b/type-tests/prop-types/vueComponent.type.spec.ts index bfa2f18..f9e13c1 100644 --- a/type-tests/prop-types/vueComponent.type.spec.ts +++ b/type-tests/prop-types/vueComponent.type.spec.ts @@ -28,6 +28,27 @@ describe('vueComponentProp().optional', () => { }); }); +describe('vueComponentProp().nullable', () => { + describe('Vue 2.6', () => { + expectAssignable>(vueComponentProp().nullable); + expectNotAssignable>(vueComponentProp().nullable); + + expectType>( + createVue2Component(vueComponentProp().nullable), + ); + }); + + describe('Vue 2.7', () => { + expectAssignable>(vueComponentProp().nullable); + expectNotAssignable>(vueComponentProp().nullable); + }); + + describe('Vue 3', () => { + expectAssignable>(vueComponentProp().nullable); + expectNotAssignable>(vueComponentProp().nullable); + }); +}); + describe('vueComponentProp().withDefault', () => { describe('Vue 2.6', () => { expectAssignable>(vueComponentProp().withDefault('foo'));