Different generic types in object

How can I get different types for the Config K type by having it nested inside a type like MyType as seen below?

type Config<K> = {
  value: K;
  onUpdate: (value: K) => void;
}

type MyType<F extends string> = {
  [K in F]: <V>() => Config<V>;
}

// I want this to be possible
const hello: MyType<'setup1'|'setup2'> = {
  setup1: () => ({
    value: { hello: 'world' },
    onUpdate: record => console.log(record.hello),
  }),
  setup2: () => ({
    value: { goodbye: 'world' },
    onUpdate: record => console.log(record.goodbye),
  }),
};

TS Playground

I get this error Type '{ hello: string; }' is not assignable to type 'V'. 'V' could be instantiated with an arbitrary type which could be unrelated to '{ hello: string; }'.(2322) when trying this.

1 answer

  • answered 2022-05-04 10:47 Ovidijus Parsiunas

    Unfortunately this is not possible because <V>() => Config<V> is not assigning any real types to Config, hence the generic parameter K in type Config<K> is arbitrary and cannot hold any value.

    To help TypeScript determine the type of K, you will need to tell it what it can be during run time by adding more generics to MyType. I have noticed that the only property that tends to vary in the objects of your example is the key name, hence you can denote which setup should have which key name as follows:

    const hello: MyType<{'setup1' : 'hello', 'setup2' : 'goodbye' }> = {
    

    This can then be parsed by the types as follows:

    type Config<K extends string> = {
      value: { [F in K]: string };
      onUpdate: (value: { [F in K]: string }) => void;
    }
    
    type MyType<F extends { [key: string]: string }> = {
      [K in keyof F]: () => Config<F[K]>;
    }
    

    Playground link.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum