0

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",
};
rudolph schmitz
  • 293
  • 3
  • 11
  • I don't think it's possible to do that within a type. You could possibly do it with the help of a helper function by a doing a variation of: https://stackoverflow.com/questions/60131681/make-sure-array-has-all-types-from-a-union – zecuria Nov 29 '21 at 00:23
  • However given you're using it within react I don't think that will work. The closest I can come up with is if you change fields from an array to an object. Then you can enforce all the keys map to the `initState`. If that works I can type up an answer for you. – zecuria Nov 29 '21 at 00:24
  • @zecuria Yeah that works, give it a shot, please! :) – rudolph schmitz Nov 29 '21 at 00:36

1 Answers1

1

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

zecuria
  • 728
  • 4
  • 9
  • Alright yeah, this is a good idea. This is more straightforward than doing a bunch of helper functions. I'll give this route a shot. Thanks and accepted. – rudolph schmitz Nov 29 '21 at 00:55