Typescript create type that uses other field in a dynamic way

Typescript create type that uses other field in a dynamic way

Problem Description:

There’s a couple of questions related to this but none I could find that match my requirements.

I wish to create a factory that, based on the type, requires a factory for each key of that object that contains the value and the entire object. For example:

type Row = {
  foo: string
  bar: number
  baz: unknown
}

const factory: MyMagicType<Row> = [{
  field: 'foo',
  // Infers value as string
  factory: (value, obj) => ..
}, {
  field: 'bar',
  // Infers value as number
  factory: (value, obj) => ..
}]
^also throws that 'baz' hasn't been populated

I have tried using generics for this but got stuck.

type MyMagicType<TObj extends Record<string, unknown>, TField extends keyof TObj> {
  field: TField,
  factory: (val: TObj[TField], source: TObj) => any
}[]

But this doesn’t work due to the field needing to be inferred rather than passed into the generic.

How can I omit the TField but still let it infer from field?

Solution – 1

Not sure how you want to type the second parameter and the return value of your factory functions, but here is a possible implementation of MyMagicType that types the first parameter correctly:

type Row = {
  foo: string
  bar: number
  baz: unknown
};

type MyMagicType<T extends object> = Array<{
  [K in keyof T]: {
    field: K,
    factory: (value: T[K], obj: any) => any,
  }
}[keyof T]>;

const factory: MyMagicType<Row> = [{
  field: 'foo',
  // Infers value as string
  factory: (value, obj) => undefined
}, {
  field: 'bar',
  // Infers value as number
  factory: (value, obj) => undefined
}];

TypeScript playground

Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject