Home > Blockchain >  How do I use mapped types to ensure all nested children are represented?
How do I use mapped types to ensure all nested children are represented?

Time:09-14

Given a type and variable:

type Form = {
  controls: {
    [key: string]: any;
  }
}

const form: Form = {
  controls: {
    firstName: {},
    lastName: {},
  },
};

I want to create a type which is an object containing all keys of form.controls with a value type of string ie:

const formControlsWithStrings = {
  firstName: 'foo',
  lastName: 'bar',
};

I have tried this:

type FormControlsWithStrings<T extends Form> = 
 { [key in keyof T['controls']] : string }

however if I use it to type formControlsWithStrings above, it enforces the string value type, but not that the keys are equivalent -it does not require all keys to be present, and I can add new keys.

Why doesn't this work, and how can I get it to work?

Thanks

Stackblitz: https://stackblitz.com/edit/typescript-sxvspk?file=index.ts

CodePudding user response:

That's because the type of form is Form which allows for any string key.

If you let TS infer the type for form then it's gonna work as expected:

type Form = {
  controls: {
    [key: string]: any;
  };
};

const form = {
  controls: {
    firstName: {},
    lastName: {},
  },
};

type FormControlsWithStrings<T extends Form> = {
  [key in keyof T['controls']]: string;
};

const formControlsWithStrings: FormControlsWithStrings<typeof form> = {
  firstName: 'abc',
  // lastName: 'def' // should not compile when commmented as it a key of form
  foo: 'bar', // should not compile as it is not present in form variable
};
  • Related