Is it possible to make a mapped type property optional conditionally?
Consider this type
type Definition {
name: string,
defaultImplementation?: ImplementationType
}
and a record of them:
type DefinitionMap = Record<string, Definition>
I would like to make a mapped type that has an implementation that is optional if the input is provided, but the mapped type implementation required if it wasn't.
For an DefinitionMap like this
{
foo: { name: 'x' },
bar: { name: 'y', defaultImplementation: { /*...*/ } }
}
I would like to have a mapped type like
{
foo: ImplementationType,
bar?: ImplementationType
}
I've been trying to use conditionals and add undefined to the type, but that is not working.
type ImplementationMap<T extends DefinitionMap> = {
[K in keyof T]: T[K] extends { defaultImplementation: any }
? ImplementationType | undefined
: ImplementationType
}
I know that the conditional branches behave how I want them to, but adding undefined doesn't actually make the field optional.
I'm assuming DefinitionMap should be Record<string, Definition> (instead of Record<string, A>).
Try this:
// Gets the keys of T whose values are assignable to V
type KeysMatching<T, V> = {[K in keyof T]: T[K] extends V ? K : never}[keyof T]
type ImplementationMap<T extends DefinitionMap> =
// A partial (all properties are optional) record for all the keys
Partial<Record<keyof T, ImplementationType>> &
// Require ImplementationType for all the keys that do not have defaultImplementation
Record<KeysMatching<T, { defaultImplementation?: undefined }>, ImplementationType>
/*
Test is equivalent to
{
foo: ImplementationType,
bar?: ImplementationType,
baz: ImplementationType
}
*/
type Test = ImplementationMap<{
foo: { name: 'x' },
bar: { name: 'y', defaultImplementation: { /*...*/ } },
baz: { name: 'z', defaultImplementaiton: undefined }
}>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With