Skip to content

Commit

Permalink
fix(types): make properties optional
Browse files Browse the repository at this point in the history
  • Loading branch information
jquense committed Dec 15, 2020
1 parent d4e3799 commit 495ae84
Show file tree
Hide file tree
Showing 11 changed files with 69 additions and 68 deletions.
6 changes: 0 additions & 6 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,10 @@ const base = {
}),
],
external: [
'lodash/has',
'lodash/cloneDeepWith',
'lodash/toArray',
'lodash/mapKeys',
'lodash/mapValues',
'lodash/snakeCase',
'lodash/camelCase',
'toposort',
'fn-name',
'synchronous-promise',
'property-expr',
],
};
Expand Down
3 changes: 1 addition & 2 deletions src/Condition.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import has from 'lodash/has';
import isSchema from './util/isSchema';
import Reference from './Reference';
import { SchemaLike } from './types';
Expand Down Expand Up @@ -37,7 +36,7 @@ class Condition<T extends SchemaLike = SchemaLike> {
return;
}

if (!has(options, 'is'))
if (!('is' in options))
throw new TypeError('`is:` is required for `when()` conditions');

if (!options.then && !options.otherwise)
Expand Down
10 changes: 0 additions & 10 deletions src/globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1 @@
declare module 'lodash/has' {
// eslint-disable-next-line no-inner-declarations
function has<T extends {}, Key extends PropertyKey>(
obj: T,
prop: Key,
): obj is T & Record<Key, unknown> {
return has(obj, prop);
}

export default has;
}
2 changes: 1 addition & 1 deletion src/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export let array: Required<ArrayLocale> = {
length: '${path} must be have ${length} items',
};

export default Object.assign(Object.create(null), {
export default Object.assign(Object.create(null) as {}, {
mixed,
string,
number,
Expand Down
37 changes: 19 additions & 18 deletions src/object.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import has from 'lodash/has';
import snakeCase from 'lodash/snakeCase';
import camelCase from 'lodash/camelCase';
import mapKeys from 'lodash/mapKeys';
import mapValues from 'lodash/mapValues';
import { getter } from 'property-expr';

import { object as locale } from './locale';
Expand All @@ -26,6 +23,7 @@ import type {
NotNull,
ToggleDefault,
_,
MakePartial,
} from './util/types';
import type Reference from './Reference';
import Lazy from './Lazy';
Expand Down Expand Up @@ -73,13 +71,11 @@ export type TypeOfShape<Shape extends ObjectShape> = {
// : never
// : K;

export type AssertsShape<S extends ObjectShape> = {
[K in keyof S]: S[K] extends TypedSchema
? S[K]['__outputType']
: S[K] extends Reference
? unknown
: never;
};
export type AssertsShape<S extends ObjectShape> = MakePartial<
{
[K in keyof S]: FieldType<S[K], '__outputType'>;
}
>;

export type PartialSchema<S extends ObjectShape> = {
[K in keyof S]: S[K] extends BaseSchema ? ReturnType<S[K]['optional']> : S[K];
Expand Down Expand Up @@ -176,7 +172,7 @@ export default class ObjectSchema<
let isChanged = false;
for (const prop of props) {
let field = fields[prop];
let exists = has(value!, prop);
let exists = prop in value!;

if (field) {
let fieldValue;
Expand Down Expand Up @@ -446,9 +442,9 @@ export default class ObjectSchema<
let fromGetter = getter(from, true);

return this.transform((obj) => {
if (obj == null) return obj;
if (!obj) return obj;
let newObj = obj;
if (has(obj, from)) {
if (from in obj) {
newObj = { ...obj };
if (!alias) delete newObj[from];

Expand Down Expand Up @@ -490,7 +486,12 @@ export default class ObjectSchema<
}

transformKeys(fn: (key: string) => string) {
return this.transform((obj) => obj && mapKeys(obj, (__, key) => fn(key)));
return this.transform((obj) => {
if (!obj) return obj;
const result: AnyObject = {};
for (const key of Object.keys(obj)) result[fn(key)] = obj[key];
return result;
});
}

camelCase() {
Expand All @@ -507,7 +508,8 @@ export default class ObjectSchema<

describe(options?: ResolveOptions<TConfig['context']>) {
let base = super.describe(options) as SchemaObjectDescription;
base.fields = mapValues(this.fields, (value, key) => {
base.fields = {};
for (const [key, value] of Object.entries(this.fields)) {
let innerOptions = options;
if (innerOptions?.value) {
innerOptions = {
Expand All @@ -516,9 +518,8 @@ export default class ObjectSchema<
value: innerOptions.value[key],
};
}

return value.describe(innerOptions);
});
base.fields[key] = value.describe(innerOptions);
}
return base;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ export default abstract class BaseSchema<
recursive: true,
nullable: false,
optional: true,
// presence: 'nonnullable',
...options?.spec,
};

Expand Down Expand Up @@ -524,6 +523,7 @@ export default abstract class BaseSchema<
if (defaultValue == null) {
return defaultValue;
}

return typeof defaultValue === 'function'
? defaultValue.call(this)
: cloneDeep(defaultValue);
Expand Down
9 changes: 0 additions & 9 deletions src/setLocale.js

This file was deleted.

17 changes: 17 additions & 0 deletions src/setLocale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import locale from './locale';

type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};

type Locale = DeepPartial<typeof locale>;

export default function setLocale(custom: Locale) {
Object.keys(custom).forEach((type) => {
// @ts-ignore
Object.keys(custom[type]!).forEach((method) => {
// @ts-ignore
locale[type][method] = custom[type][method];
});
});
}
24 changes: 12 additions & 12 deletions src/util/createValidation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import mapValues from 'lodash/mapValues';
import ValidationError from '../ValidationError';
import Ref from '../Reference';
import {
Expand Down Expand Up @@ -81,17 +80,18 @@ export default function createValidation(config: {
}

function createError(overrides: CreateErrorOptions = {}) {
const nextParams = mapValues(
{
value,
originalValue,
label,
path: overrides.path || path,
...params,
...overrides.params,
},
resolve,
);
const nextParams = {
value,
originalValue,
label,
path: overrides.path || path,
...params,
...overrides.params,
};

type Keys = (keyof typeof nextParams)[];
for (const key of Object.keys(nextParams) as Keys)
nextParams[key] = resolve(nextParams[key]);

const error = new ValidationError(
ValidationError.formatError(overrides.message || message, nextParams),
Expand Down
16 changes: 7 additions & 9 deletions src/util/sortFields.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import has from 'lodash/has';
// @ts-expect-error
import toposort from 'toposort';
import { split } from 'property-expr';
Expand All @@ -22,16 +21,15 @@ export default function sortFields(
if (!~excludes.indexOf(`${key}-${node}`)) edges.push([key, node]);
}

for (const key in fields)
if (has(fields, key)) {
let value = fields[key];
for (const key of Object.keys(fields)) {
let value = fields[key];

if (!~nodes.indexOf(key)) nodes.push(key);
if (!~nodes.indexOf(key)) nodes.push(key);

if (Ref.isRef(value) && value.isSibling) addNode(value.path, key);
else if (isSchema(value) && 'deps' in value)
value.deps.forEach((path) => addNode(path, key));
}
if (Ref.isRef(value) && value.isSibling) addNode(value.path, key);
else if (isSchema(value) && 'deps' in value)
value.deps.forEach((path) => addNode(path, key));
}

return toposort.array(nodes, edges).reverse() as string[];
}
11 changes: 11 additions & 0 deletions src/util/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ export type If<T, Y, N> = Exclude<T, undefined> extends never ? Y : N;
/* this seems to force TS to show the full type instead of all the wrapped generics */
export type _<T> = T extends {} ? { [k in keyof T]: _<T[k]> } : T;

type OptionalKeys<T extends {}> = {
[k in keyof T]: undefined extends T[k] ? k : never;
}[keyof T];

type RequiredKeys<T extends object> = Exclude<keyof T, OptionalKeys<T>>;

export type MakePartial<T extends object> = {
[k in OptionalKeys<T>]?: T[k];
} &
{ [k in RequiredKeys<T>]: T[k] };

//
// Schema Config
//
Expand Down

0 comments on commit 495ae84

Please sign in to comment.