Skip to content

Commit

Permalink
Try improving handling of unions
Browse files Browse the repository at this point in the history
The goal is to handle "complex" unions (unions that aren't merely subsets of a single primitive type) without interfering with simple enumerated-constant-style unions (such as `'development' | 'production' | 'test'`) or booleans.

Fixes #2848
  • Loading branch information
joshkel committed Sep 29, 2022
1 parent d7afcd5 commit 0462bbb
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
21 changes: 20 additions & 1 deletion lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -740,11 +740,30 @@ declare namespace Joi {

type NullableType<T> = undefined | null | T

type IsPrimitiveSubset<T> =
[T] extends [string]
? true
: [T] extends [number]
? true
: [T] extends [bigint]
? true
: [T] extends [boolean]
? true
: [T] extends [symbol]
? true
: [T] extends [null]
? true
: [T] extends [undefined]
? true
: false;

type IsUnion<T, U extends T = T> =
T extends unknown ? [U] extends [T] ? false : true : false;

type IsNonPrimitiveSubsetUnion<T> = true extends IsUnion<T> ? true extends IsPrimitiveSubset<T> ? false : true : false;

type ObjectPropertiesSchema<T = any> =
true extends IsUnion<Exclude<T, undefined | null>>
true extends IsNonPrimitiveSubsetUnion<Exclude<T, undefined | null>>
? Joi.AlternativesSchema
: T extends NullableType<string>
? Joi.StringSchema
Expand Down
8 changes: 7 additions & 1 deletion test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1263,11 +1263,13 @@ const userSchema2 = Joi.object<User>().keys({
interface Comment {
text: string;
user: User;
isNew: boolean;
}

const commentSchemaObject = Joi.object<Comment, true>({
text: Joi.string().required(),
user: userSchemaObject
user: userSchemaObject,
isNew: Joi.boolean().required(),
});

interface Comment2 {
Expand All @@ -1287,11 +1289,15 @@ const commentSchemaObject2 = Joi.object<Comment2, true>({
interface CommentWithAlternatives {
text: string;
user: string | User;
type: 'topLevel' | 'pingback' | 'reply';
reported: boolean | number;
}

const commentWithAlternativesSchemaObject = Joi.object<CommentWithAlternatives, true>({
text: Joi.string().required(),
user: Joi.alternatives(Joi.string(), userSchemaObject),
type: Joi.string().required().valid('topLevel', 'pingback', 'reply'),
reported: Joi.alternatives(Joi.boolean(), Joi.number()),
});

expect.error(userSchema2.keys({ height: Joi.number() }));
Expand Down

0 comments on commit 0462bbb

Please sign in to comment.