简体   繁体   中英

How can I generate a type from the properties values of a typed object in Typescript?

Say I had an interface that described a library that items that look like this:

interface MyItem {
  category: string,
  title: string
}

Now I have a config file full of those MyItems:

const myLibrary: MyItem[] = [
  {
    category: "dogs",
    title: "Fuzzy quadrupeds" 
  },
  { 
    category: "snakes",
    title: "Slithery reptiles"
  },
  ...
]

Now, I'd like to create a type that consists of all the category in MyItem[]

If I do this: type Category = typeof MyItem[number]["category"] I get string .

If I remove the typing from myLibrary (ie const myLibrary = [ {...} ] ) and get what I want:

That means that type Category = typeof MyItem[number]["category"] gives me the union type I want of dogs | snakes dogs | snakes but of course I lose the typing when creating new items in my config file.

We want to restrict the items in myLibrary such that they must implement MyItem , but we want to do it in a way that preserves specific types of specific items and doesn't broaden the type to just MyItem .

It is hard to do that just with assigning a type to the constant. A commonly-used pattern is to create the constant through an identity function. With a function we can use extends syntax to ensure that T extends MyItem[] while keeping T specific.

I had to use as const to get the literal category names, so I also had to allow readonly in the function arguments.

interface MyItem {
  category: string,
  title: string
}

const buildLibrary = <T extends readonly MyItem[]>(library: T): T => library;

const myLibrary = buildLibrary([
  {
    category: "dogs",
    title: "Fuzzy quadrupeds" 
  },
  { 
    category: "snakes",
    title: "Slithery reptiles"
  }
] as const);

type Categories = (typeof myLibrary)[number]['category'] // "dogs" | "snakes"

Typescript Playground Link

If I understand you right, you want this: How to create enum like type in TypeScript? and then specify MyItem as

interface MyItem: {
    category: MyDogSnakeType,
    title: string
}

Do not complicate


type Categorías = 'Food' | 'categoy1' | 'cstegory2'

interface MyItem {
  category: Categories;
  title: string
}

const myLibrary: MyItem[] = [
  {
    category: "dogs",
    title: "Fuzzy quadrupeds" 
  },
  { 
    category: "snakes",
    title: "Slithery reptiles"
  },
  ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM