Home > Back-end >  Extract a key/value object type from the properties of an array of objects in Typescript
Extract a key/value object type from the properties of an array of objects in Typescript

Time:04-07

I have a constant array of objects that use the same properties. Something like this:

const allData = [{
  name: 'info', content: Info
},{
  name: 'other', content: Other
},{
  ...
}];

Now I want to create a variable that after some other code is run, will map these into an object where the keys are the strings of the name property and the values are instances of the content property. Given that, I want to know how I can define such a type in Typescript that would basically extract those properties from my constant so that it becomes like this in the end:

Type ContentInstances = {
  info: Info,
  other: Other 
  ...
}

Is there such a way using typeof and other things on Typescript to achieve this dynamically based on allData constant?

EDIT Basically at a later stage, I will have something like this:

let myVar: ContentInstances;
...
myVar = allData.reduce((obj, value) => {
  obj[value.name] = new value.content(customParam);
  return obj;
}, {})

CodePudding user response:

The following should do the trick:

const allData = [
  {
    name: "info",
    content: { hey: "you" },
  },
  {
    name: "other",
    content: { bro: "chill" },
  },
] as const;

type ContentInstances = {
  [K in typeof allData[number]["name"]]: Extract<
    typeof allData[number],
    { name: K }
  >["content"];
};

declare const foo: ContentInstances;

foo.info.hey;
foo.other.bro;

CodePudding user response:

You are going to need to first type your constant variable with as const to allow for TypeScript to have smart inference on the types of literals. After that, you can combine this with mapped types to create a new type.

const allData = [{
  name: 'info', content: { hey: "you" }
}, {
  name: 'other', content: { bro: "chill" }
}] as const;

// the intersection lets us pick out the types in the array that match
// the given `name` property type
type ContentInstances =
  { [K in typeof allData[number]["name"]]: typeof allData[number] & { readonly name: K } }

const foo: ContentInstances["info"] = {
  name: "info",
  content: {
    hey: "you",
    // @ts-expect-error this correctly fails
    asdf: 2,
  }
};

TypeScript Playground Link

  • Related