Skip to content

Commit

Permalink
Add undefinedable schema #385
Browse files Browse the repository at this point in the history
  • Loading branch information
fabian-hiller committed Aug 27, 2024
1 parent 6376e05 commit 6f470fd
Show file tree
Hide file tree
Showing 127 changed files with 1,562 additions and 5 deletions.
4 changes: 4 additions & 0 deletions library/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to the library will be documented in this file.

## vX.X.X (Month DD, YYYY)

- Add `undefinedable` and `undefinedableAsync` schema (issue #385)

## v0.39.0 (August 24, 2024)

- Add support for `exactOptionalPropertyTypes` config (issue #385)
Expand Down
20 changes: 20 additions & 0 deletions library/src/methods/getDefault/getDefault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type {
NullishSchemaAsync,
OptionalSchema,
OptionalSchemaAsync,
UndefinedableSchema,
UndefinedableSchemaAsync,
} from '../../schemas/index.ts';
import type {
BaseIssue,
Expand Down Expand Up @@ -41,6 +43,15 @@ export type InferDefault<
| BaseSchema<unknown, unknown, BaseIssue<unknown>>
| BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,
unknown
>
| UndefinedableSchema<
BaseSchema<unknown, unknown, BaseIssue<unknown>>,
unknown
>
| UndefinedableSchemaAsync<
| BaseSchema<unknown, unknown, BaseIssue<unknown>>
| BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,
unknown
>,
> = TSchema extends
| NullableSchema<
Expand Down Expand Up @@ -70,6 +81,15 @@ export type InferDefault<
| BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,
infer TDefault
>
| UndefinedableSchema<
BaseSchema<unknown, unknown, BaseIssue<unknown>>,
infer TDefault
>
| UndefinedableSchemaAsync<
| BaseSchema<unknown, unknown, BaseIssue<unknown>>
| BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,
infer TDefault
>
? [TDefault] extends [never]
? undefined
: TDefault extends () => MaybePromise<InferInput<TSchema>>
Expand Down
11 changes: 11 additions & 0 deletions library/src/methods/unwrap/unwrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import type {
NullishSchemaAsync,
OptionalSchema,
OptionalSchemaAsync,
UndefinedableSchema,
UndefinedableSchemaAsync,
} from '../../schemas/index.ts';
import type {
BaseIssue,
Expand Down Expand Up @@ -75,6 +77,15 @@ export function unwrap<
| BaseSchema<unknown, unknown, BaseIssue<unknown>>
| BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,
unknown
>
| UndefinedableSchema<
BaseSchema<unknown, unknown, BaseIssue<unknown>>,
unknown
>
| UndefinedableSchemaAsync<
| BaseSchema<unknown, unknown, BaseIssue<unknown>>
| BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,
unknown
>,
>(schema: TSchema): TSchema['wrapped'] {
return schema.wrapped;
Expand Down
1 change: 1 addition & 0 deletions library/src/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export * from './symbol/index.ts';
export * from './tuple/index.ts';
export * from './tupleWithRest/index.ts';
export * from './undefined/index.ts';
export * from './undefinedable/index.ts';
export * from './union/index.ts';
export * from './unknown/index.ts';
export * from './variant/index.ts';
Expand Down
4 changes: 4 additions & 0 deletions library/src/schemas/looseObject/looseObject.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
type StringIssue,
type StringSchema,
} from '../string/index.ts';
import type { UndefinedableSchema } from '../undefinedable/index.ts';
import { looseObject, type LooseObjectSchema } from './looseObject.ts';
import type { LooseObjectIssue } from './types.ts';

Expand Down Expand Up @@ -46,6 +47,7 @@ describe('looseObject', () => {
key3: NullishSchema<StringSchema<undefined>, never>;
key4: ObjectSchema<{ key: NumberSchema<undefined> }, never>;
key5: SchemaWithPipe<[StringSchema<undefined>, ReadonlyAction<string>]>;
key6: UndefinedableSchema<StringSchema<undefined>, 'bar'>;
},
undefined
>;
Expand All @@ -58,6 +60,7 @@ describe('looseObject', () => {
key3?: string | null | undefined;
key4: { key: number };
key5: string;
key6: string | undefined;
} & { [key: string]: unknown }
>();
});
Expand All @@ -70,6 +73,7 @@ describe('looseObject', () => {
key3?: string | null | undefined;
key4: { key: number };
readonly key5: string;
key6: string;
} & { [key: string]: unknown }
>();
});
Expand Down
4 changes: 4 additions & 0 deletions library/src/schemas/looseObject/looseObjectAsync.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
type StringIssue,
type StringSchema,
} from '../string/index.ts';
import type { UndefinedableSchema } from '../undefinedable/index.ts';
import {
looseObjectAsync,
type LooseObjectSchemaAsync,
Expand Down Expand Up @@ -51,6 +52,7 @@ describe('looseObjectAsync', () => {
key3: NullishSchema<StringSchema<undefined>, never>;
key4: ObjectSchema<{ key: NumberSchema<undefined> }, never>;
key5: SchemaWithPipe<[StringSchema<undefined>, ReadonlyAction<string>]>;
key6: UndefinedableSchema<StringSchema<undefined>, 'bar'>;
},
undefined
>;
Expand All @@ -63,6 +65,7 @@ describe('looseObjectAsync', () => {
key3?: string | null | undefined;
key4: { key: number };
key5: string;
key6: string | undefined;
} & { [key: string]: unknown }
>();
});
Expand All @@ -75,6 +78,7 @@ describe('looseObjectAsync', () => {
key3?: string | null | undefined;
key4: { key: number };
readonly key5: string;
key6: string;
} & { [key: string]: unknown }
>();
});
Expand Down
4 changes: 4 additions & 0 deletions library/src/schemas/object/object.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
type StringIssue,
type StringSchema,
} from '../string/index.ts';
import type { UndefinedableSchema } from '../undefinedable/index.ts';
import { object, type ObjectSchema } from './object.ts';
import type { ObjectIssue } from './types.ts';

Expand Down Expand Up @@ -45,6 +46,7 @@ describe('object', () => {
key3: NullishSchema<StringSchema<undefined>, never>;
key4: ObjectSchema<{ key: NumberSchema<undefined> }, never>;
key5: SchemaWithPipe<[StringSchema<undefined>, ReadonlyAction<string>]>;
key6: UndefinedableSchema<StringSchema<undefined>, 'bar'>;
},
undefined
>;
Expand All @@ -56,6 +58,7 @@ describe('object', () => {
key3?: string | null | undefined;
key4: { key: number };
key5: string;
key6: string | undefined;
}>();
});

Expand All @@ -66,6 +69,7 @@ describe('object', () => {
key3?: string | null | undefined;
key4: { key: number };
readonly key5: string;
key6: string;
}>();
});

Expand Down
4 changes: 4 additions & 0 deletions library/src/schemas/object/objectAsync.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
type StringIssue,
type StringSchema,
} from '../string/index.ts';
import type { UndefinedableSchema } from '../undefinedable/index.ts';
import { objectAsync, type ObjectSchemaAsync } from './objectAsync.ts';
import type { ObjectIssue } from './types.ts';

Expand Down Expand Up @@ -45,6 +46,7 @@ describe('objectAsync', () => {
key3: NullishSchema<StringSchema<undefined>, never>;
key4: ObjectSchemaAsync<{ key: NumberSchema<undefined> }, never>;
key5: SchemaWithPipe<[StringSchema<undefined>, ReadonlyAction<string>]>;
key6: UndefinedableSchema<StringSchema<undefined>, 'bar'>;
},
undefined
>;
Expand All @@ -56,6 +58,7 @@ describe('objectAsync', () => {
key3?: string | null | undefined;
key4: { key: number };
key5: string;
key6: string | undefined;
}>();
});

Expand All @@ -66,6 +69,7 @@ describe('objectAsync', () => {
key3?: string | null | undefined;
key4: { key: number };
readonly key5: string;
key6: string;
}>();
});

Expand Down
4 changes: 4 additions & 0 deletions library/src/schemas/objectWithRest/objectWithRest.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
type StringIssue,
type StringSchema,
} from '../string/index.ts';
import type { UndefinedableSchema } from '../undefinedable/index.ts';
import { objectWithRest, type ObjectWithRestSchema } from './objectWithRest.ts';
import type { ObjectWithRestIssue } from './types.ts';

Expand Down Expand Up @@ -55,6 +56,7 @@ describe('objectWithRest', () => {
key3: NullishSchema<StringSchema<undefined>, never>;
key4: ObjectSchema<{ key: NumberSchema<undefined> }, never>;
key5: SchemaWithPipe<[StringSchema<undefined>, ReadonlyAction<string>]>;
key6: UndefinedableSchema<StringSchema<undefined>, 'bar'>;
},
BooleanSchema<undefined>,
undefined
Expand All @@ -68,6 +70,7 @@ describe('objectWithRest', () => {
key3?: string | null | undefined;
key4: { key: number };
key5: string;
key6: string | undefined;
} & { [key: string]: boolean }
>();
});
Expand All @@ -80,6 +83,7 @@ describe('objectWithRest', () => {
key3?: string | null | undefined;
key4: { key: number };
readonly key5: string;
key6: string;
} & { [key: string]: boolean }
>();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
type StringIssue,
type StringSchema,
} from '../string/index.ts';
import type { UndefinedableSchema } from '../undefinedable/index.ts';
import {
objectWithRestAsync,
type ObjectWithRestSchemaAsync,
Expand Down Expand Up @@ -58,6 +59,7 @@ describe('objectWithRestAsync', () => {
key3: NullishSchema<StringSchema<undefined>, never>;
key4: ObjectSchema<{ key: NumberSchema<undefined> }, never>;
key5: SchemaWithPipe<[StringSchema<undefined>, ReadonlyAction<string>]>;
key6: UndefinedableSchema<StringSchema<undefined>, 'bar'>;
},
BooleanSchema<undefined>,
undefined
Expand All @@ -71,6 +73,7 @@ describe('objectWithRestAsync', () => {
key3?: string | null | undefined;
key4: { key: number };
key5: string;
key6: string | undefined;
} & { [key: string]: boolean }
>();
});
Expand All @@ -83,6 +86,7 @@ describe('objectWithRestAsync', () => {
key3?: string | null | undefined;
key4: { key: number };
readonly key5: string;
key6: string;
} & { [key: string]: boolean }
>();
});
Expand Down
4 changes: 4 additions & 0 deletions library/src/schemas/strictObject/strictObject.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
type StringIssue,
type StringSchema,
} from '../string/index.ts';
import type { UndefinedableSchema } from '../undefinedable/index.ts';
import { strictObject, type StrictObjectSchema } from './strictObject.ts';
import type { StrictObjectIssue } from './types.ts';

Expand Down Expand Up @@ -46,6 +47,7 @@ describe('strictObject', () => {
key3: NullishSchema<StringSchema<undefined>, never>;
key4: ObjectSchema<{ key: NumberSchema<undefined> }, never>;
key5: SchemaWithPipe<[StringSchema<undefined>, ReadonlyAction<string>]>;
key6: UndefinedableSchema<StringSchema<undefined>, 'bar'>;
},
undefined
>;
Expand All @@ -57,6 +59,7 @@ describe('strictObject', () => {
key3?: string | null | undefined;
key4: { key: number };
key5: string;
key6: string | undefined;
}>();
});

Expand All @@ -67,6 +70,7 @@ describe('strictObject', () => {
key3?: string | null | undefined;
key4: { key: number };
readonly key5: string;
key6: string;
}>();
});

Expand Down
4 changes: 4 additions & 0 deletions library/src/schemas/strictObject/strictObjectAsync.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
type StringIssue,
type StringSchema,
} from '../string/index.ts';
import type { UndefinedableSchema } from '../undefinedable/index.ts';
import {
strictObjectAsync,
type StrictObjectSchemaAsync,
Expand Down Expand Up @@ -51,6 +52,7 @@ describe('strictObjectAsync', () => {
key3: NullishSchema<StringSchema<undefined>, never>;
key4: ObjectSchema<{ key: NumberSchema<undefined> }, never>;
key5: SchemaWithPipe<[StringSchema<undefined>, ReadonlyAction<string>]>;
key6: UndefinedableSchema<StringSchema<undefined>, 'bar'>;
},
undefined
>;
Expand All @@ -62,6 +64,7 @@ describe('strictObjectAsync', () => {
key3?: string | null | undefined;
key4: { key: number };
key5: string;
key6: string | undefined;
}>();
});

Expand All @@ -72,6 +75,7 @@ describe('strictObjectAsync', () => {
key3?: string | null | undefined;
key4: { key: number };
readonly key5: string;
key6: string;
}>();
});

Expand Down
3 changes: 3 additions & 0 deletions library/src/schemas/undefinedable/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './undefinedable.ts';
export * from './undefinedableAsync.ts';
export * from './types.ts';
24 changes: 24 additions & 0 deletions library/src/schemas/undefinedable/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type {
BaseIssue,
BaseSchema,
BaseSchemaAsync,
DefaultAsync,
DefaultValue,
InferOutput,
NonOptional,
} from '../../types/index.ts';

/**
* Infer undefinedable output type.
*/
export type InferUndefinedableOutput<
TWrapped extends
| BaseSchema<unknown, unknown, BaseIssue<unknown>>
| BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,
TDefault extends DefaultAsync<TWrapped, undefined>,
> = [TDefault] extends [never]
? InferOutput<TWrapped> | undefined
: // FIXME: For schemas that transform the input to `undefined`, this
// implementation may result in an incorrect output type
| NonOptional<InferOutput<TWrapped>>
| Extract<DefaultValue<TDefault>, undefined>;
Loading

0 comments on commit 6f470fd

Please sign in to comment.