Home > Enterprise >  How to enforce Typescript to check that all keys in an object are present in array, where said keys
How to enforce Typescript to check that all keys in an object are present in array, where said keys

Time:11-29

Is there any easy to way ensure all keys of an object, are present on another object property?

For example:

export interface Field<T> {
  formKey: Extract<keyof T, string>;
  label: string;
  text: string;
}

export interface FormProps<T> {
  initState: T;
  fields: Field<T>[];
  title: string;
}


const initState = {
 name: 'whatever',
 description: 'whocares'
}

Is it possible for Typescript to check that for fields, all keys present in initState, exist in that array of objects, where those keys get assigned to formKey?

So if you passed:

const mockExposureProps: FormProps<FormInfo.Exposure> = {
  fields: [
    {
      formKey: "description",
      label: "mock-label",
      text: "mock-text",
    },
  ],
  initState: {
    description: "mock-desc",
    name: "mock-name",
  },
  title: "cool title",
};

Typescript would let you know, you didn't also pass an object that has a formKey of name

EDIT:

The closest I can get is this:

export interface Field<T> {
  formKey: Pick<T, keyof T>; // Change occurred here
  label: string;
  text: string;
}

But then my data structure needs to change to:

const mockExposureProps: FormProps<FormInfo.Exposure> = {
  fields: [
    {
      formKey: { // Change occurred here
        description: 'mock-desc',
      }
    },
      label: "mock-label",
      text: "mock-text",
    },
  ],
  initState: {
    description: "mock-desc",
    name: "mock-name",
  },
  title: "cool title",
};

CodePudding user response:

While it is possible to enforce it in a very round about way by doing using a helper function as shown: Make sure array has all types from a union

I don't think that would really work in the context of react and using it within a component. Instead what I would recommend is changing the type definition to:

export interface Field {
  label: string;
  text: string;
}

export interface FormProps<T> {
  initState: T;
  fields: Record<keyof T, Field>;
  title: string;
}

This way you can easily enforce that each of the keys present in initState must also be present in field.

Playground

  • Related