如何从 Typescript 中类型化对象的属性值生成类型?

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

假设我有一个 interface 描述了一个图书馆,其中的项目如下所示:

interface MyItem {
  category: string,
  title: string
}

现在我有一个包含所有 MyItems 的配置文件:

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

现在,我想创建一个包含 MyItem[]

中所有 category 的类型

如果我这样做: type Category = typeof MyItem[number]["category"] 我得到 string.

如果我从 myLibrary 中删除输入(即 const myLibrary = [ {...} ])并得到我想要的:

这意味着 type Category = typeof MyItem[number]["category"] 为我提供了 dogs | snakes 我想要的联合类型,但当然我在配置文件中创建新项目时丢失了输入。

如果我没理解错的话,您需要这样:How to create enum like type in TypeScript? 然后将 MyItem 指定为

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

我们想限制 myLibrary 中的项目,以便它们必须实现 MyItem,但我们希望以一种保留特定类型的特定项目并且不扩大输入 MyItem.

仅通过为常量分配类型很难做到这一点。一种常用的模式是通过恒等函数创建常量。通过一个函数,我们可以使用 extends 语法来确保 T extends MyItem[] 同时保持 T 特定。

我必须使用 as const 来获取文字类别名称,所以我还必须在函数参数中允许 readonly

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

不要复杂化


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"
  },
  ...