Skip to content

Commit

Permalink
consider optional properties as optional keys in ObjectType
Browse files Browse the repository at this point in the history
  • Loading branch information
pgayvallet committed Apr 17, 2020
1 parent eefafa2 commit 3c28c21
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
24 changes: 24 additions & 0 deletions packages/kbn-config-schema/src/types/object_type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import { schema } from '..';
import { TypeOf } from './object_type';

test('returns value by default', () => {
const type = schema.object({
Expand Down Expand Up @@ -350,3 +351,26 @@ test('unknowns = `ignore` affects only own keys', () => {
})
).toThrowErrorMatchingInlineSnapshot(`"[foo.baz]: definition for this key is missing"`);
});

test('handles optional properties', () => {
const type = schema.object({
required: schema.string(),
optional: schema.maybe(schema.string()),
});

type SchemaType = TypeOf<typeof type>;

let foo: SchemaType = {
required: 'foo',
};
foo = {
required: 'hello',
optional: undefined,
};
foo = {
required: 'hello',
optional: 'bar',
};

expect(foo).toBeDefined();
});
22 changes: 20 additions & 2 deletions packages/kbn-config-schema/src/types/object_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,26 @@ export type Props = Record<string, Type<any>>;

export type TypeOf<RT extends Type<any>> = RT['type'];

type OptionalProperties<Base extends Props> = Pick<
Base,
{
[Key in keyof Base]: undefined extends TypeOf<Base[Key]> ? Key : never;
}[keyof Base]
>;

type RequiredProperties<Base extends Props> = Pick<
Base,
{
[Key in keyof Base]: undefined extends TypeOf<Base[Key]> ? never : Key;
}[keyof Base]
>;

// Because of https://github.com/Microsoft/TypeScript/issues/14041
// this might not have perfect _rendering_ output, but it will be typed.
export type ObjectResultType<P extends Props> = Readonly<{ [K in keyof P]: TypeOf<P[K]> }>;
export type ObjectResultType<P extends Props> = Readonly<
{ [K in keyof OptionalProperties<P>]?: TypeOf<P[K]> } &
{ [K in keyof RequiredProperties<P>]: TypeOf<P[K]> }
>;

interface UnknownOptions {
/**
Expand All @@ -41,7 +58,8 @@ interface UnknownOptions {
}

export type ObjectTypeOptions<P extends Props = any> = TypeOptions<
{ [K in keyof P]: TypeOf<P[K]> }
{ [K in keyof OptionalProperties<P>]?: TypeOf<P[K]> } &
{ [K in keyof RequiredProperties<P>]: TypeOf<P[K]> }
> &
UnknownOptions;

Expand Down
6 changes: 3 additions & 3 deletions src/core/server/http/router/validator/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,23 +170,23 @@ export class RouteValidator<P = {}, Q = {}, B = {}> {
* @internal
*/
public getParams(data: unknown, namespace?: string): Readonly<P> {
return this.validate(this.config.params, this.options.unsafe?.params, data, namespace);
return this.validate(this.config.params, this.options.unsafe?.params, data, namespace) as P;
}

/**
* Get validated query params
* @internal
*/
public getQuery(data: unknown, namespace?: string): Readonly<Q> {
return this.validate(this.config.query, this.options.unsafe?.query, data, namespace);
return this.validate(this.config.query, this.options.unsafe?.query, data, namespace) as Q;
}

/**
* Get validated body
* @internal
*/
public getBody(data: unknown, namespace?: string): Readonly<B> {
return this.validate(this.config.body, this.options.unsafe?.body, data, namespace);
return this.validate(this.config.body, this.options.unsafe?.body, data, namespace) as B;
}

/**
Expand Down

0 comments on commit 3c28c21

Please sign in to comment.