Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use interface instead of type for all Base types #259

Merged
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
fd86987
Use `interface` instead of `type` for all Base types
Saeris Nov 19, 2023
990140a
Refactor Fallback and Default methods, Add Schema Type Predicates
Saeris Nov 21, 2023
cc38e4f
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Nov 21, 2023
5b483f4
Fix file extensions lint errors
Saeris Nov 22, 2023
a6bbcd1
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Nov 22, 2023
a1584f1
Add jsdoc `@param` and `@returns` required by linting rules
Saeris Nov 22, 2023
c08f732
Resolve Flatten type errors
Saeris Nov 22, 2023
7f84338
Fix broken export for `intersectAsync`
Saeris Nov 22, 2023
cab5616
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Dec 5, 2023
a89b486
Fix eslint error
Saeris Dec 5, 2023
3b2d314
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Dec 5, 2023
1b516da
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Jan 6, 2024
5078f72
Resolve lint errors (no-extra-semi)
Saeris Jan 6, 2024
27dec16
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Jan 8, 2024
6949d2d
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Jan 18, 2024
c2dc365
Fix extra semi errors from merge
Saeris Jan 18, 2024
527a05c
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Jan 18, 2024
e5c79ca
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Jan 19, 2024
0a426bb
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Jan 21, 2024
e195488
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Jan 24, 2024
0676aff
Fix merge errors
Saeris Jan 24, 2024
0604c26
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Feb 5, 2024
bb424a0
Fix formatting
Saeris Feb 5, 2024
b6a2fb2
Merge branch 'main' into feat/use-interface-for-base-types
fabian-hiller Feb 17, 2024
0a5889a
Fix types and exports of fallback method
fabian-hiller Feb 17, 2024
fe36ae1
Add `isOfType` utility and refactor type guard implementations
Saeris Feb 27, 2024
9574d5d
Merge branch 'feat/use-interface-for-base-types' of https://github.co…
Saeris Feb 27, 2024
2a28529
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Mar 4, 2024
48ce458
Merge branch 'main' into feat/use-interface-for-base-types
Saeris Mar 4, 2024
02b17d5
run prettier and fix lint warnings
Saeris Mar 4, 2024
2cefacc
Add Default and DefaultAsync type and refactor codebase
fabian-hiller Mar 6, 2024
114b1f8
Add Fallback and FallbackAsync type and refactor codebase
fabian-hiller Mar 6, 2024
e08af7f
Refactor getDefaults and getFallbacks method
fabian-hiller Mar 6, 2024
03e95e3
Undo changes of NestedPath type in flatten
fabian-hiller Mar 6, 2024
7e79352
Rename hasType to isOfType and refactor codebase
fabian-hiller Mar 6, 2024
2f77fc2
Add Default and Fallback to API reference of website
fabian-hiller Mar 6, 2024
de1d857
Update changelog of library
fabian-hiller Mar 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions library/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to the library will be documented in this file.

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

- Add `Default` and `DefaultAsync` type and refactor codebase
- Add `Fallback` and `FallbackAsync` type and refactor codebase
- Refactor `getDefaults` and `getDefaultsAsync` method (pull request #259)
- Refactor `getFallbacks` and `getFallbacksAsync` method (pull request #259)
- Remove deprecated properties of `safeParse` and `safeParseAsync` method
- Fix `NestedPath` type of `flatten` for async schemas (issue #456)

Expand Down
14 changes: 8 additions & 6 deletions library/src/methods/fallback/fallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ import { schemaResult } from '../../utils/index.ts';
import { getFallback } from '../getFallback/index.ts';
import type { FallbackInfo } from './types.ts';

// TODO: Should we create a Fallback and Default type to simplify the generics?
/**
* Fallback type.
*/
export type Fallback<TSchema extends BaseSchema> =
| Output<TSchema>
| ((info?: FallbackInfo) => Output<TSchema>);

/**
* Schema with fallback type.
*/
export type SchemaWithFallback<
TSchema extends BaseSchema = BaseSchema,
TFallback extends
| Output<TSchema>
| ((info?: FallbackInfo) => Output<TSchema>) = Output<TSchema>,
TFallback extends Fallback<TSchema> = Fallback<TSchema>,
> = TSchema & {
/**
* The fallback value.
Expand All @@ -30,8 +33,7 @@ export type SchemaWithFallback<
*/
export function fallback<
TSchema extends BaseSchema,
const TFallback extends // TODO: Should we also allow `undefined`
Output<TSchema> | ((info?: FallbackInfo) => Output<TSchema>),
const TFallback extends Fallback<TSchema>, // TODO: Should we also allow `undefined`
>(
schema: TSchema,
fallback: TFallback
Expand Down
17 changes: 9 additions & 8 deletions library/src/methods/fallback/fallbackAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ import { schemaResult } from '../../utils/index.ts';
import { getFallbackAsync } from '../getFallback/index.ts';
import type { FallbackInfo } from './types.ts';

/**
* Fallback async type.
*/
export type FallbackAsync<TSchema extends BaseSchemaAsync> =
| Output<TSchema>
| ((info?: FallbackInfo) => Output<TSchema> | Promise<Output<TSchema>>);

/**
* Schema with fallback async type.
*/
export type SchemaWithFallbackAsync<
TSchema extends BaseSchemaAsync = BaseSchemaAsync,
TFallback extends
| Output<TSchema>
| ((
info?: FallbackInfo
) => Output<TSchema> | Promise<Output<TSchema>>) = Output<TSchema>,
TFallback extends FallbackAsync<TSchema> = FallbackAsync<TSchema>,
> = TSchema & {
/**
* The fallback value.
Expand All @@ -30,9 +33,7 @@ export type SchemaWithFallbackAsync<
*/
export function fallbackAsync<
TSchema extends BaseSchemaAsync,
const TFallback extends
| Output<TSchema>
| ((info?: FallbackInfo) => Output<TSchema> | Promise<Output<TSchema>>),
const TFallback extends FallbackAsync<TSchema>,
>(
schema: TSchema,
fallback: TFallback
Expand Down
18 changes: 10 additions & 8 deletions library/src/methods/getDefault/getDefault.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import type { BaseSchema, Output } from '../../types/index.ts';
import type { BaseSchema, Default } from '../../types/index.ts';
import type { DefaultValue } from './types.ts';

/**
* Schema with maybe default type.
*/
export type SchemaWithMaybeDefault<TSchema extends BaseSchema = BaseSchema> =
TSchema & {
/**
* The optional default value.
*/
default?: Output<TSchema> | (() => Output<TSchema> | undefined);
};
export type SchemaWithMaybeDefault<
TSchema extends BaseSchema = BaseSchema,
TDefault extends Default<TSchema> = Default<TSchema>,
> = TSchema & {
/**
* The optional default value.
*/
default?: TDefault;
};

/**
* Returns the default value of the schema.
Expand Down
10 changes: 3 additions & 7 deletions library/src/methods/getDefault/getDefaultAsync.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BaseSchemaAsync, Output } from '../../types/index.ts';
import type { BaseSchemaAsync, DefaultAsync } from '../../types/index.ts';
import type { SchemaWithMaybeDefault } from './getDefault.ts';
import type { DefaultValue } from './types.ts';

Expand All @@ -7,16 +7,12 @@ import type { DefaultValue } from './types.ts';
*/
export type SchemaWithMaybeDefaultAsync<
TSchema extends BaseSchemaAsync = BaseSchemaAsync,
TDefault extends DefaultAsync<TSchema> = DefaultAsync<TSchema>,
> = TSchema & {
/**
* The optional default value.
*/
default?:
| Output<TSchema>
| (() =>
| Output<TSchema>
| Promise<Output<TSchema> | undefined>
| undefined);
default?: TDefault;
};

/**
Expand Down
8 changes: 4 additions & 4 deletions library/src/methods/getDefault/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Output } from '../../types/index.ts';
import type { Input } from '../../types/index.ts';
import type { SchemaWithMaybeDefault } from './getDefault.ts';
import type { SchemaWithMaybeDefaultAsync } from './getDefaultAsync.ts';

Expand All @@ -7,10 +7,10 @@ import type { SchemaWithMaybeDefaultAsync } from './getDefaultAsync.ts';
*/
export type DefaultValue<
TSchema extends SchemaWithMaybeDefault | SchemaWithMaybeDefaultAsync,
> = TSchema['default'] extends Output<TSchema> | undefined
> = TSchema['default'] extends Input<TSchema> | undefined
? TSchema['default']
: TSchema['default'] extends () => Output<TSchema> | undefined
: TSchema['default'] extends () => Input<TSchema> | undefined
? ReturnType<TSchema['default']>
: TSchema['default'] extends () => Promise<Output<TSchema> | undefined>
: TSchema['default'] extends () => Promise<Input<TSchema> | undefined>
? Awaited<ReturnType<TSchema['default']>>
: undefined;
44 changes: 20 additions & 24 deletions library/src/methods/getDefaults/getDefaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type {
TupleItems,
TupleSchema,
} from '../../schemas/index.ts';
import type { BaseSchema } from '../../types/index.ts';
import type { BaseSchema } from '../../types/schema.ts';
import { hasType } from '../../utils/index.ts';
import {
getDefault,
type SchemaWithMaybeDefault,
Expand All @@ -26,32 +27,27 @@ export function getDefaults<
TSchema extends SchemaWithMaybeDefault<
BaseSchema | ObjectSchema<ObjectEntries, any> | TupleSchema<TupleItems, any>
>,
>(schema: TSchema): DefaultValues<TSchema> {
// Create defaults variable
let defaults: any;

// If schema contains a default function, set its default value
>(schema: TSchema): DefaultValues<TSchema> | undefined {
Copy link

@aboqasem aboqasem Mar 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, as per the documentation for getDefaults:

The difference to getDefault is that for objects and tuples without an explicit default value, this function recursively returns the default values of the subschemas instead of undefined.

Did that change?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it should work just the same. All unit tests passed, so I do not expect any bugs, but maybe we are missing something. Please create an issue if you encounter any problems.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok thanks. It just broke the type when I upgraded so I was wondering.

Copy link
Owner

@fabian-hiller fabian-hiller Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to share your code if you thing something is wrong on our side.

// If schema has default, return its value
if (schema.default !== undefined) {
defaults = getDefault(schema);
return getDefault(schema);
}

// Otherwise, check if schema is of kind object or tuple
} else if ('type' in schema) {
// If it is an object schema, set object with default value of each entry
if (schema.type === 'object') {
defaults = {};
for (const key in schema.entries) {
defaults[key] = getDefaults(schema.entries[key]);
}
// If it is an object schema, return default of each entry
if (hasType(schema, 'object')) {
return Object.fromEntries(
Object.entries(schema.entries).map(([key, value]) => [
key,
getDefaults(value),
])
) as DefaultValues<TSchema>;
}

// If it is a tuple schema, set array with default value of each item
} else if (schema.type === 'tuple') {
defaults = [];
for (let key = 0; key < schema.items.length; key++) {
defaults.push(getDefaults(schema.items[key]));
}
}
// If it is a tuple schema, return default of each item
if (hasType(schema, 'tuple')) {
return schema.items.map(getDefaults) as DefaultValues<TSchema>;
}

// Return default values
return defaults;
// Otherwise, return undefined
return undefined;
}
48 changes: 24 additions & 24 deletions library/src/methods/getDefaults/getDefaultsAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type {
TupleSchema,
TupleSchemaAsync,
} from '../../schemas/index.ts';
import type { BaseSchema, BaseSchemaAsync } from '../../types/index.ts';
import type { BaseSchema, BaseSchemaAsync } from '../../types/schema.ts';
import { hasType } from '../../utils/index.ts';
import {
getDefaultAsync,
type SchemaWithMaybeDefault,
Expand Down Expand Up @@ -39,32 +40,31 @@ export async function getDefaultsAsync<
| ObjectSchemaAsync<ObjectEntriesAsync, any>
| TupleSchemaAsync<TupleItemsAsync, any>
>,
>(schema: TSchema): Promise<DefaultValues<TSchema>> {
// Create defaults variable
let defaults: any;

// If schema contains a default function, set its default value
>(schema: TSchema): Promise<DefaultValues<TSchema> | undefined> {
// If schema contains default, return its value
if (schema.default !== undefined) {
defaults = await getDefaultAsync(schema);
return getDefaultAsync(schema);
}

// Otherwise, check if schema is of kind object or tuple
} else if ('type' in schema) {
// If it is an object schema, set object with default value of each entry
if (schema.type === 'object') {
defaults = {};
for (const key in schema.entries) {
defaults[key] = await getDefaultsAsync(schema.entries[key]);
}
// If it is an object schema, return default of each entry
if (hasType(schema, 'object')) {
return Object.fromEntries(
await Promise.all(
Object.entries(schema.entries).map(async ([key, value]) => [
key,
await getDefaultsAsync(value),
])
)
) as DefaultValues<TSchema>;
}

// If it is a tuple schema, set array with default value of each item
} else if (schema.type === 'tuple') {
defaults = [];
for (let key = 0; key < schema.items.length; key++) {
defaults.push(await getDefaultsAsync(schema.items[key]));
}
}
// If it is a tuple schema, return default of each item
if (hasType(schema, 'tuple')) {
return Promise.all(
schema.items.map(getDefaultsAsync)
) as DefaultValues<TSchema>;
}

// Return default values
return defaults;
// Otherwise, return undefined
return undefined;
}
19 changes: 11 additions & 8 deletions library/src/methods/getFallback/getFallback.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import type { BaseSchema, Output } from '../../types/index.ts';
import type { BaseSchema } from '../../types/index.ts';
import type { Fallback } from '../fallback/index.ts';
import type { FallbackInfo } from '../fallback/types.ts';
import type { FallbackValue } from './types.ts';

/**
* Schema with maybe fallback type.
*/
export type SchemaWithMaybeFallback<TSchema extends BaseSchema = BaseSchema> =
TSchema & {
/**
* The optional fallback value.
*/
fallback?: Output<TSchema> | ((info?: FallbackInfo) => Output<TSchema>);
};
export type SchemaWithMaybeFallback<
TSchema extends BaseSchema = BaseSchema,
TFallback extends Fallback<TSchema> = Fallback<TSchema>,
> = TSchema & {
/**
* The optional fallback value.
*/
fallback?: TFallback;
};

/**
* Returns the fallback value of the schema.
Expand Down
8 changes: 4 additions & 4 deletions library/src/methods/getFallback/getFallbackAsync.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { BaseSchemaAsync, Output } from '../../types/index.ts';
import type { BaseSchemaAsync } from '../../types/index.ts';
import type { FallbackAsync } from '../fallback/index.ts';
import type { FallbackInfo } from '../fallback/types.ts';
import type { SchemaWithMaybeFallback } from './getFallback.ts';
import type { FallbackValue } from './types.ts';
Expand All @@ -8,13 +9,12 @@ import type { FallbackValue } from './types.ts';
*/
export type SchemaWithMaybeFallbackAsync<
TSchema extends BaseSchemaAsync = BaseSchemaAsync,
TFallback extends FallbackAsync<TSchema> = FallbackAsync<TSchema>,
> = TSchema & {
/**
* The optional fallback value.
*/
fallback?:
| Output<TSchema>
| ((info?: FallbackInfo) => Output<TSchema> | Promise<Output<TSchema>>);
fallback?: TFallback;
};

/**
Expand Down
44 changes: 20 additions & 24 deletions library/src/methods/getFallbacks/getFallbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type {
TupleItems,
TupleSchema,
} from '../../schemas/index.ts';
import type { BaseSchema } from '../../types/index.ts';
import type { BaseSchema } from '../../types/schema.ts';
import { hasType } from '../../utils/index.ts';
import {
getFallback,
type SchemaWithMaybeFallback,
Expand All @@ -26,32 +27,27 @@ export function getFallbacks<
TSchema extends SchemaWithMaybeFallback<
BaseSchema | ObjectSchema<ObjectEntries, any> | TupleSchema<TupleItems, any>
>,
>(schema: TSchema): FallbackValues<TSchema> {
// Create fallbacks variable
let fallbacks: any;

// If schema has a fallback, set its value
>(schema: TSchema): FallbackValues<TSchema> | undefined {
// If schema has fallback, return its value
if (schema.fallback !== undefined) {
fallbacks = getFallback(schema);
return getFallback(schema);
}

// Otherwise, check if schema is of kind object or tuple
} else if ('type' in schema) {
// If it is an object schema, set object with fallback value of each entry
if (schema.type === 'object') {
fallbacks = {};
for (const key in schema.entries) {
fallbacks[key] = getFallbacks(schema.entries[key]);
}
// If it is an object schema, return fallback of each entry
if (hasType(schema, 'object')) {
return Object.fromEntries(
Object.entries(schema.entries).map(([key, value]) => [
key,
getFallbacks(value),
])
) as FallbackValues<TSchema>;
}

// If it is a tuple schema, set array with fallback value of each item
} else if (schema.type === 'tuple') {
fallbacks = [];
for (let key = 0; key < schema.items.length; key++) {
fallbacks.push(getFallbacks(schema.items[key]));
}
}
// If it is a tuple schema, return fallback of each item
if (hasType(schema, 'tuple')) {
return schema.items.map(getFallbacks) as FallbackValues<TSchema>;
}

// Return fallback values
return fallbacks;
// Otherwise, return undefined
return undefined;
}
Loading
Loading