Allow Only Keys of Interface in TypeScript

In TypeScript, you can create an object with any keys or allow only certain keys.

Any Keys Allowed

To use any keys, indicate that any string is a valid key:

type TrackedValues = Record<string, boolean>

const tracked = { any: true, thing: true }

Only Allow Keys from an Interface

If you have an interface and want to use those as the only valid keys, you can do so:

export interface ValidValues {
  field1: string;
  field2: string;
}

type TrackedValidValues = { [K in keyof ValidValues]?: boolean }

const tracked: TrackedValidValues = { field1: true, fieldUnknown: true }

Running tsc on this code will yield the error:

Type '{ field1: true; fieldUnknown: boolean; }' is not assignable to type 'TrackedValidValues'.
  Object literal may only specify known properties, and 'fieldUnknown' does not exist in type 'TrackedValidValues'.(2322)

This is because fieldUnknown is not a key in the ValidValues interface.

The key here is in the typing of generic K must be in the array of keys on this interface, and that's shown in the dynamic property syntax of [K in keyof ValidValues].

Only Allow Keys from Union Type

If you have a union on string literals and want to use those as the only valid keys, you can do so:

type ValidValues = 'field1' | 'field2'

type TrackedValidValues = { [K in ValidValues]?: boolean }

const tracked: TrackedValidValues = { field1: true, fieldUnknown: true }

Running tsc on this code will yield the error:

Type '{ field1: true; fieldUnknown: boolean; }' is not assignable to type 'TrackedValidValues'.
  Object literal may only specify known properties, and 'fieldUnknown' does not exist in type 'TrackedValidValues'.(2322)

Similar to the interface, we are looking for inclusion of K in a collection of ValidValues, but ValidValues is already a collection, so we drop the keyof operator.