Kibana version: 7.7+ (on master)
Describe the bug:
If you use schema.maybe() on an object , the prop is only marked as T | undefined, but it should be optional (perhaps both, rather than instead).


Steps to reproduce:
const schemaWithOptional = schema.object({
prop: schema.maybe(schema.string()),
});
export type SchemaWithOptional = TypeOf<typeof schemaWithOptional>;
SchemaWithOptional - the prop field is marked as string | undefined, meaning you can't omit the prop field and have to set it as undefined.interface SchemaWithOptional {
prop: string | undefined;
}
Expected behavior:
The type should be:
interface SchemaWithOptional {
prop?: string;
}
or perhaps:
interface SchemaWithOptional {
prop?: string | undefined;
}
Pinging @elastic/kibana-platform (Team:Platform)
I think The type should be
interface SchemaWithOptional {
prop?: string | undefined;
}
However, technically, this requires the parent object schema's Type to be dependant on the children schema types, which I'm not sure is doable in typescript.
Will take a look.
This all goes down to
Would need to find a TS way to check if TypeOf<P[K]> extends MaybeType
So, after a few hours hating typescript:
This can be fixed by changing
type ObjectResultType<P extends Props> = Readonly<{ [K in keyof P]: TypeOf<P[K]> }>;
with
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]
>;
export type ObjectResultType<P extends Props> = Readonly<
{ [K in keyof OptionalProperties<P>]?: TypeOf<P[K]> } &
{ [K in keyof RequiredProperties<P>]: TypeOf<P[K]> }
>;
The TypeOf is fixed:
const type = schema.object({
required: schema.string(),
optional: schema.maybe(schema.string()),
});
type SchemaType = TypeOf<typeof type>;
let foo: SchemaType = { // no error
required: 'foo',
};
foo = { // no error
required: 'hello',
optional: undefined,
};
foo = { // no error
required: 'hello',
optional: 'bar',
};
foo = { // error
optional: 'bar',
};
foo = { // error
};
However this change causes the router validator (src/core/server/http/router/validator/validator.ts) to just implode, with

This is directly related to this type
However this file is a very sensible piece of TS magic, and I couldn't find a proper way to fix the typings without force casting everywhere.
If someone wants to have a look, feel free.
haha sorry if I broke you @pgayvallet
Most helpful comment
haha sorry if I broke you @pgayvallet