diff --git a/README.md b/README.md index 8775af613..21e102679 100644 --- a/README.md +++ b/README.md @@ -166,15 +166,17 @@ import { - [`date.min(limit: Date | string | Ref, message?: string | function): Schema`](#dateminlimit-date--string--ref-message-string--function-schema) - [`date.max(limit: Date | string | Ref, message?: string | function): Schema`](#datemaxlimit-date--string--ref-message-string--function-schema) - [array](#array) - - [`array.of(type: Schema): Schema`](#arrayoftype-schema-schema) - - [`array.length(length: number | Ref, message?: string | function): Schema`](#arraylengthlength-number--ref-message-string--function-schema) - - [`array.min(limit: number | Ref, message?: string | function): Schema`](#arrayminlimit-number--ref-message-string--function-schema) - - [`array.max(limit: number | Ref, message?: string | function): Schema`](#arraymaxlimit-number--ref-message-string--function-schema) - - [`array.ensure(): Schema`](#arrayensure-schema) + - [`array.of(type: Schema): this`](#arrayoftype-schema-this) + - [`array.json(): this`](#arrayjson-this) + - [`array.length(length: number | Ref, message?: string | function): this`](#arraylengthlength-number--ref-message-string--function-this) + - [`array.min(limit: number | Ref, message?: string | function): this`](#arrayminlimit-number--ref-message-string--function-this) + - [`array.max(limit: number | Ref, message?: string | function): this`](#arraymaxlimit-number--ref-message-string--function-this) + - [`array.ensure(): this`](#arrayensure-this) - [`array.compact(rejector: (value) => boolean): Schema`](#arraycompactrejector-value--boolean-schema) - [object](#object) - [Object schema defaults](#object-schema-defaults) - [`object.shape(fields: object, noSortEdges?: Array<[string, string]>): Schema`](#objectshapefields-object-nosortedges-arraystring-string-schema) + - [`object.json(): this`](#objectjson-this) - [`object.concat(schemaB: ObjectSchema): ObjectSchema`](#objectconcatschemab-objectschema-objectschema) - [`object.pick(keys: string[]): Schema`](#objectpickkeys-string-schema) - [`object.omit(keys: string[]): Schema`](#objectomitkeys-string-schema) diff --git a/src/array.ts b/src/array.ts index d6cec856b..10b2e0db4 100644 --- a/src/array.ts +++ b/src/array.ts @@ -9,6 +9,7 @@ import type { Callback, Message, Maybe, + Optionals, } from './types'; import ValidationError from './ValidationError'; import type Reference from './Reference'; @@ -27,6 +28,8 @@ import Schema, { SchemaInnerTypeDescription, SchemaSpec } from './schema'; import { ResolveOptions } from './Condition'; import parseJson from 'parse-json'; +type InnerType = T extends Array ? I : never; + export type RejectorFn = ( value: any, index: number, @@ -36,19 +39,18 @@ export type RejectorFn = ( export function create( type?: ISchema, ) { - return new ArraySchema(type as any); + return new ArraySchema(type as any); } export default class ArraySchema< - T, + TIn extends any[] | null | undefined, TContext, TDefault = undefined, TFlags extends Flags = '', - TIn extends any[] | null | undefined = T[] | undefined, > extends Schema { - innerType?: ISchema; + readonly innerType?: ISchema, TContext>; - constructor(type?: ISchema) { + constructor(type?: ISchema, TContext>) { super({ type: 'array', check(v: any): v is NonNullable { @@ -60,15 +62,13 @@ export default class ArraySchema< this.innerType = type; } - private get _subType() { - return this.innerType; - } - protected _cast(_value: any, _opts: InternalOptions) { const value = super._cast(_value, _opts); - //should ignore nulls here - if (!this._typeCheck(value) || !this.innerType) return value; + // should ignore nulls here + if (!this._typeCheck(value) || !this.innerType) { + return value; + } let isChanged = false; const castArray = value.map((v, idx) => { @@ -151,6 +151,7 @@ export default class ArraySchema< clone(spec?: SchemaSpec) { const next = super.clone(spec); + // @ts-expect-error readonly next.innerType = this.innerType; return next; } @@ -160,22 +161,23 @@ export default class ArraySchema< return this.transform(parseJson); } - concat>( - schema: ArraySchema, + concat, IC, ID, IF extends Flags>( + schema: ArraySchema, ): ArraySchema< - Concat, + Concat, TContext & IC, Extract extends never ? TDefault : ID, - TFlags | IF, - Concat + TFlags | IF >; concat(schema: this): this; concat(schema: any): any { let next = super.concat(schema) as this; + // @ts-expect-error readonly next.innerType = this.innerType; if (schema.innerType) + // @ts-expect-error readonly next.innerType = next.innerType ? // @ts-expect-error Lazy doesn't have concat and will break next.innerType.concat(schema.innerType) @@ -184,7 +186,9 @@ export default class ArraySchema< return next; } - of(schema: ISchema): ArraySchema { + of( + schema: ISchema, + ): ArraySchema, TContext, TFlags> { // FIXME: this should return a new instance of array without the default to be let next = this.clone(); @@ -194,8 +198,8 @@ export default class ArraySchema< printValue(schema), ); - // FIXME(ts): - next.innerType = schema as any; + // @ts-expect-error readonly + next.innerType = schema; return next as any; } @@ -243,8 +247,6 @@ export default class ArraySchema< }); } - // ArraySchema, NonNullable> - ensure() { return this.default(() => [] as any).transform( (val: TIn, original: any) => { @@ -285,35 +287,30 @@ export default class ArraySchema< create.prototype = ArraySchema.prototype; export default interface ArraySchema< - T, + TIn extends any[] | null | undefined, TContext, TDefault = undefined, TFlags extends Flags = '', - TIn extends any[] | null | undefined = T[] | undefined, > extends Schema { default>( def: Thunk, - ): ArraySchema, TIn>; + ): ArraySchema>; - defined( - msg?: Message, - ): ArraySchema>; - optional(): ArraySchema; + defined(msg?: Message): ArraySchema, TContext, TDefault, TFlags>; + optional(): ArraySchema; required( msg?: Message, - ): ArraySchema>; - notRequired(): ArraySchema>; + ): ArraySchema, TContext, TDefault, TFlags>; + notRequired(): ArraySchema, TContext, TDefault, TFlags>; - nullable( - msg?: Message, - ): ArraySchema; - nonNullable(): ArraySchema>; + nullable(msg?: Message): ArraySchema; + nonNullable(): ArraySchema, TContext, TDefault, TFlags>; strip( enabled: false, - ): ArraySchema>; + ): ArraySchema>; strip( enabled?: true, - ): ArraySchema>; + ): ArraySchema>; } diff --git a/test/types/types.ts b/test/types/types.ts index 63ea70bad..e699af62f 100644 --- a/test/types/types.ts +++ b/test/types/types.ts @@ -392,7 +392,7 @@ date: { const blDefined = bool().default(false); - // $ExpectType boolean + // $ExpectType false blDefined.getDefault(); // $ExpectType false | undefined @@ -502,6 +502,9 @@ Array: { // $ExpectType (string | undefined)[] | undefined array(string()).cast(null); + // $ExpectType (string | undefined)[] | null + array().defined().nullable().of(string()).cast(null); + // $ExpectType string[] | undefined array(string().required()).validateSync(null);