Home > Back-end >  TypeScript, infer keys from object
TypeScript, infer keys from object

Time:09-02

I have an object that contains all the keys that should be valid in a new object I need to make with some modifications to the values of said keys.

Example:

// This object contains all the keys i want to use in a different object below -> "one" and "two".
const myObject: { [id: string]: string } = {
    one: 'foo',
    two: 'bar',
};

This is how I've tried to extract the keys:

type MyType = {
  [T in keyof typeof myObject]: {
    bar: string
  };
}

If I hover over MyType in VSCode i see this:

type MyType = {
    [x: string]: {
        bar: string;
    };
}

This is obviously wrong, as it should not accept any string, but the set of keys defined in myObject.

And this is how I've tried to use the new type:

const test: MyType = {
  one: {
    bar: 'foo'
  },
  two: {
    bar: 'string'
  },
  shouldNotBeValid: {
    bar: 'foo'
  }
}

The key "shouldNotBeValid" shouldn't be allowed, but it still passes. However, if I remove the typing of myObject, so it's like this:

const myObject = {
    one: 'foo',
    two: 'bar',
};

and then hover over MyType I get this which is correct:

type MyType = {
    one: {
        bar: string;
    };
    two: {
        bar: string;
    };
}

Is it possible to express MyType how I want, and still be able to keep typing of myObject?

CodePudding user response:

You would have to use a generic function to create the myObject variable. The generic function will constrain the type to Record<string, string> but also return the original type of the object.

const myObject = createMyObject({
    one: 'foo',
    two: 'bar',
})

function createMyObject<T extends Record<string, string>>(obj: T) {
  return obj
}

type MyType = {
  [T in keyof typeof myObject]: {
    bar: string
  };
}
// type MyType = {
//     one: {
//         bar: string;
//     };
//     two: {
//         bar: string;
//     };
// }

Playground

  • Related