From 3c28c21d06e94b44777fd544b06fc01b40b07c71 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 17 Apr 2020 13:53:35 +0200 Subject: [PATCH 1/3] consider optional properties as optional keys in ObjectType --- .../src/types/object_type.test.ts | 24 +++++++++++++++++++ .../src/types/object_type.ts | 22 +++++++++++++++-- .../server/http/router/validator/validator.ts | 6 ++--- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/packages/kbn-config-schema/src/types/object_type.test.ts b/packages/kbn-config-schema/src/types/object_type.test.ts index 47a0f5f7a5491..5ab59d1c02077 100644 --- a/packages/kbn-config-schema/src/types/object_type.test.ts +++ b/packages/kbn-config-schema/src/types/object_type.test.ts @@ -18,6 +18,7 @@ */ import { schema } from '..'; +import { TypeOf } from './object_type'; test('returns value by default', () => { const type = schema.object({ @@ -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; + + let foo: SchemaType = { + required: 'foo', + }; + foo = { + required: 'hello', + optional: undefined, + }; + foo = { + required: 'hello', + optional: 'bar', + }; + + expect(foo).toBeDefined(); +}); diff --git a/packages/kbn-config-schema/src/types/object_type.ts b/packages/kbn-config-schema/src/types/object_type.ts index 5a50e714a5931..2c76cd5760132 100644 --- a/packages/kbn-config-schema/src/types/object_type.ts +++ b/packages/kbn-config-schema/src/types/object_type.ts @@ -26,9 +26,26 @@ export type Props = Record>; export type TypeOf> = RT['type']; +type OptionalProperties = Pick< + Base, + { + [Key in keyof Base]: undefined extends TypeOf ? Key : never; + }[keyof Base] +>; + +type RequiredProperties = Pick< + Base, + { + [Key in keyof Base]: undefined extends TypeOf ? 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

= Readonly<{ [K in keyof P]: TypeOf }>; +export type ObjectResultType

= Readonly< + { [K in keyof OptionalProperties

]?: TypeOf } & + { [K in keyof RequiredProperties

]: TypeOf } +>; interface UnknownOptions { /** @@ -41,7 +58,8 @@ interface UnknownOptions { } export type ObjectTypeOptions

= TypeOptions< - { [K in keyof P]: TypeOf } + { [K in keyof OptionalProperties

]?: TypeOf } & + { [K in keyof RequiredProperties

]: TypeOf } > & UnknownOptions; diff --git a/src/core/server/http/router/validator/validator.ts b/src/core/server/http/router/validator/validator.ts index 97dd2bc894f81..c484b1ee5a825 100644 --- a/src/core/server/http/router/validator/validator.ts +++ b/src/core/server/http/router/validator/validator.ts @@ -170,7 +170,7 @@ export class RouteValidator

{ * @internal */ public getParams(data: unknown, namespace?: string): Readonly

{ - 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; } /** @@ -178,7 +178,7 @@ export class RouteValidator

{ * @internal */ public getQuery(data: unknown, namespace?: string): Readonly { - 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; } /** @@ -186,7 +186,7 @@ export class RouteValidator

{ * @internal */ public getBody(data: unknown, namespace?: string): Readonly { - 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; } /** From 58e27560722efa1ed47c7a01ff37c3133ae4771f Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 17 Apr 2020 15:14:10 +0200 Subject: [PATCH 2/3] fix type on security config --- src/core/server/http/router/validator/validator.ts | 4 ++-- x-pack/plugins/security/server/config.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/server/http/router/validator/validator.ts b/src/core/server/http/router/validator/validator.ts index c484b1ee5a825..98bdaeca24949 100644 --- a/src/core/server/http/router/validator/validator.ts +++ b/src/core/server/http/router/validator/validator.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ValidationError, Type, schema, ObjectType } from '@kbn/config-schema'; +import { ValidationError, Type, schema, ObjectType, TypeOf } from '@kbn/config-schema'; import { Stream } from 'stream'; import { RouteValidationError } from './validator_error'; @@ -85,7 +85,7 @@ type RouteValidationResultType | undefined> = T extends RouteValidationFunction ? ReturnType['value'] : T extends Type - ? ReturnType + ? TypeOf : undefined >; diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index 97ff7d00a4336..fdbb03d3e708a 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -104,8 +104,8 @@ const providersConfigSchema = schema.object( { validate(config) { const checks = { sameOrder: new Map(), sameName: new Map() }; - for (const [providerType, providerGroup] of Object.entries(config)) { - for (const [providerName, { enabled, order }] of Object.entries(providerGroup ?? {})) { + for (const [providerType, providerGroup] of Object.entries(config)) { + for (const [providerName, { enabled, order }] of Object.entries(providerGroup ?? {})) { if (!enabled) { continue; } From 996cd136e5993e53918425019f95bfae0962936d Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 17 Apr 2020 15:41:37 +0200 Subject: [PATCH 3/3] fix ObjectTypeOptions --- packages/kbn-config-schema/src/types/object_type.ts | 5 +---- x-pack/plugins/security/server/config.ts | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/kbn-config-schema/src/types/object_type.ts b/packages/kbn-config-schema/src/types/object_type.ts index 2c76cd5760132..fee2d02c1bfb9 100644 --- a/packages/kbn-config-schema/src/types/object_type.ts +++ b/packages/kbn-config-schema/src/types/object_type.ts @@ -57,10 +57,7 @@ interface UnknownOptions { unknowns?: 'allow' | 'ignore' | 'forbid'; } -export type ObjectTypeOptions

= TypeOptions< - { [K in keyof OptionalProperties

]?: TypeOf } & - { [K in keyof RequiredProperties

]: TypeOf } -> & +export type ObjectTypeOptions

= TypeOptions> & UnknownOptions; export class ObjectType

extends Type> { diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index fdbb03d3e708a..97ff7d00a4336 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -104,8 +104,8 @@ const providersConfigSchema = schema.object( { validate(config) { const checks = { sameOrder: new Map(), sameName: new Map() }; - for (const [providerType, providerGroup] of Object.entries(config)) { - for (const [providerName, { enabled, order }] of Object.entries(providerGroup ?? {})) { + for (const [providerType, providerGroup] of Object.entries(config)) { + for (const [providerName, { enabled, order }] of Object.entries(providerGroup ?? {})) { if (!enabled) { continue; }