Skip to content

Commit 85ab412

Browse files
committed
kbn/config-schema: Consider maybe properties as optional keys in ObjectType (#63838)
* consider optional properties as optional keys in ObjectType * fix type on security config * fix ObjectTypeOptions
1 parent a10ae66 commit 85ab412

3 files changed

Lines changed: 55 additions & 9 deletions

File tree

packages/kbn-config-schema/src/types/object_type.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
import { schema } from '..';
21+
import { TypeOf } from './object_type';
2122

2223
test('returns value by default', () => {
2324
const type = schema.object({
@@ -350,3 +351,26 @@ test('unknowns = `ignore` affects only own keys', () => {
350351
})
351352
).toThrowErrorMatchingInlineSnapshot(`"[foo.baz]: definition for this key is missing"`);
352353
});
354+
355+
test('handles optional properties', () => {
356+
const type = schema.object({
357+
required: schema.string(),
358+
optional: schema.maybe(schema.string()),
359+
});
360+
361+
type SchemaType = TypeOf<typeof type>;
362+
363+
let foo: SchemaType = {
364+
required: 'foo',
365+
};
366+
foo = {
367+
required: 'hello',
368+
optional: undefined,
369+
};
370+
foo = {
371+
required: 'hello',
372+
optional: 'bar',
373+
};
374+
375+
expect(foo).toBeDefined();
376+
});

packages/kbn-config-schema/src/types/object_type.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,26 @@ export type Props = Record<string, Type<any>>;
2626

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

29+
type OptionalProperties<Base extends Props> = Pick<
30+
Base,
31+
{
32+
[Key in keyof Base]: undefined extends TypeOf<Base[Key]> ? Key : never;
33+
}[keyof Base]
34+
>;
35+
36+
type RequiredProperties<Base extends Props> = Pick<
37+
Base,
38+
{
39+
[Key in keyof Base]: undefined extends TypeOf<Base[Key]> ? never : Key;
40+
}[keyof Base]
41+
>;
42+
2943
// Because of https://github.com/Microsoft/TypeScript/issues/14041
3044
// this might not have perfect _rendering_ output, but it will be typed.
31-
export type ObjectResultType<P extends Props> = Readonly<{ [K in keyof P]: TypeOf<P[K]> }>;
45+
export type ObjectResultType<P extends Props> = Readonly<
46+
{ [K in keyof OptionalProperties<P>]?: TypeOf<P[K]> } &
47+
{ [K in keyof RequiredProperties<P>]: TypeOf<P[K]> }
48+
>;
3249

3350
interface UnknownOptions {
3451
/**
@@ -40,9 +57,7 @@ interface UnknownOptions {
4057
unknowns?: 'allow' | 'ignore' | 'forbid';
4158
}
4259

43-
export type ObjectTypeOptions<P extends Props = any> = TypeOptions<
44-
{ [K in keyof P]: TypeOf<P[K]> }
45-
> &
60+
export type ObjectTypeOptions<P extends Props = any> = TypeOptions<ObjectResultType<P>> &
4661
UnknownOptions;
4762

4863
export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>> {

src/core/server/http/router/validator/validator.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@
1717
* under the License.
1818
*/
1919

20-
import { ValidationError, Type, schema, ObjectType, isConfigSchema } from '@kbn/config-schema';
20+
import {
21+
ValidationError,
22+
Type,
23+
schema,
24+
ObjectType,
25+
TypeOf,
26+
isConfigSchema,
27+
} from '@kbn/config-schema';
2128
import { Stream } from 'stream';
2229
import { RouteValidationError } from './validator_error';
2330

@@ -85,7 +92,7 @@ type RouteValidationResultType<T extends RouteValidationSpec<any> | undefined> =
8592
T extends RouteValidationFunction<any>
8693
? ReturnType<T>['value']
8794
: T extends Type<any>
88-
? ReturnType<T['validate']>
95+
? TypeOf<T>
8996
: undefined
9097
>;
9198

@@ -170,23 +177,23 @@ export class RouteValidator<P = {}, Q = {}, B = {}> {
170177
* @internal
171178
*/
172179
public getParams(data: unknown, namespace?: string): Readonly<P> {
173-
return this.validate(this.config.params, this.options.unsafe?.params, data, namespace);
180+
return this.validate(this.config.params, this.options.unsafe?.params, data, namespace) as P;
174181
}
175182

176183
/**
177184
* Get validated query params
178185
* @internal
179186
*/
180187
public getQuery(data: unknown, namespace?: string): Readonly<Q> {
181-
return this.validate(this.config.query, this.options.unsafe?.query, data, namespace);
188+
return this.validate(this.config.query, this.options.unsafe?.query, data, namespace) as Q;
182189
}
183190

184191
/**
185192
* Get validated body
186193
* @internal
187194
*/
188195
public getBody(data: unknown, namespace?: string): Readonly<B> {
189-
return this.validate(this.config.body, this.options.unsafe?.body, data, namespace);
196+
return this.validate(this.config.body, this.options.unsafe?.body, data, namespace) as B;
190197
}
191198

192199
/**

0 commit comments

Comments
 (0)