Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript mapped type, add optional modifier conditionally

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.

like image 894
ptpaterson Avatar asked Sep 07 '26 18:09

ptpaterson


1 Answers

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 }
}>
like image 91
cherryblossom Avatar answered Sep 11 '26 04:09

cherryblossom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!