Constrain objec properties to be object with properties whose keys must be the same in TypeScript

Issue

I am creating a sectional form. Each section must have initial values, and a validation schema. To help the team develop in a consistent way, I want to make sure that each section looks like this:

interface Section {
  initialValues: { [key: string]: any };
  validationSchema: { [key: string]: Yup.AnySchema };
}

Is there a way to constrain initialValues and validationSchema so that they must contain the same keys?

I.e., this will work:

const section1: Section = {
  initialValues: {
    name: "",
    age: undefined // will be a number
  },
  validationSchema: {
    name: Yup.string().required(),
    age: Yup.number().required()
  }
}

Whereas this would break:

const section1: Section = {
  initialValues: {
    name: "",
    age: undefined // will be a number
  },
  validationSchema: {
    name: Yup.string().required(),
    height: Yup.number().required() // should error, as height does not exist on initialValues
    // error because we are missing the age property and its validation here
  }
}

Is there a way to accomplish such a constraint in typescript, without having to predefine the keys?

Solution

It is impossible, in this case, to make standalone type with negation. In order to make it work, in typescript, you usually need to use function arguments inference.
See example:

import Yup from 'yup'

interface Section<T, U extends T> {
    initialValues: T;
    validationSchema: U;
}

const sectionBuilder = <T, U extends T>(section: Section<T, T & U>) => {

}

sectionBuilder({
    initialValues: { name: 'hello' },
    validationSchema: { name: 'john' } // ok
})

sectionBuilder({
    initialValues: { name: 'hello' },
    validationSchema: { age: 42 } // expected error
})

sectionBuilder({
    initialValues: { name: 'hello' },
    validationSchema: { name: 'john', age: 42 } // expected error
})


Playground

Generic U in Section is an intersection of T and U or in other words, U is a set of properties which are common for initialValues and validationSchema

Answered By – captain-yossarian from Ukraine

Answer Checked By – Gilberto Lyons (AngularFixing Admin)

Leave a Reply

Your email address will not be published.