[Fixed] Is there a way to use the value from a specific key in a type declaration as the type of another key in that same declaration (in Typescript)?

Issue

Let’s say I’m trying to create a Variable type that takes a type key which has a type of string: is there a way to access the value from the key called type and use that as the type for another key in that type declaration? (Without using Generic Types)

For example,

type Variable = {
  name: string;
  required: boolean;
  type: string;
  defaultValue: Variable["type"];
}

const newWorkingVar: Variable = {
  name: "count",
  required: true,
  type: "number",
  defaultValue: 22 // This should work
}

const newErrorVar: Variable = {
  name: "count",
  required: true,
  type: "number",
  defaultValue: "test" // This should error
}

Solution

This answer is similar to @LindaPaiste’s, with the minor change that the mapping from names to types is kept in a separate type, which is then manipulated to produce Variable. For example, your mapping could look like this:

type TypeMapping = {
  number: number;
  string: string;
  boolean: boolean
  // add more here as needed
}

And then Variable could be

type Variable = { [K in keyof TypeMapping]: {
  name: string;
  required: boolean;
  type: K;
  defaultValue: TypeMapping[K];
} }[keyof TypeMapping]

This works by taking each key K from TypeMapping and transforming the property type from TypeMapping[K] to the subtype of Variable for that K (where type is the key and defaultValue is the property type). The resulting mapped type is not exactly what we want because it still has the same keys as TypeMapping. We get the union of its properties by indexing into it.

Result:

/* type Variable = {
    name: string;
    required: boolean;
    type: "string";
    defaultValue: string;
} | {
    name: string;
    required: boolean;
    type: "number";
    defaultValue: number;
} | {
    name: string;
    required: boolean;
    type: "boolean";
    defaultValue: boolean;
} */

And now you get the behavior you’re looking for:

const newWorkingVar: Variable = {
  name: "count",
  required: true,
  type: "number",
  defaultValue: 22 // okay
}

const newErrorVar: Variable = {
  name: "count",
  required: true,
  type: "number",
  defaultValue: "test" // error!
}

Playground link to code

Leave a Reply

(*) Required, Your email will not be published