如何通过属性名称在对象数组中创建适用于任何字符串值的类型?

huangapple go评论120阅读模式
英文:

How to create a type for any string value that is located in array of objects by property name?

问题

interface Icon {
    id: number,
    className: string,
    tags: string[]
}

const iconArr = [
  {
      id: 1,
      className: 'banana-class',
      tags: ['']
  },
  {
      id: 2,
      className: 'apple-class',
      tags: ['']
  }
];

我想创建一个“type”,如果除了“banana-class”或“apple-class”之外的任何值被写入,将引发错误。

在字符串数组中,我会使用`type iconStringType = typeof iconStringArr[number]`,但在我的情况下,我有一个对象数组。

谢谢!

我尝试使用:

type iconType = typeof iconArr[number]['className'];


但它不起作用 - 它允许任何字符串值。
英文:
interface Icon {
    id: number,
    className: string,
    tags: string[]
}

const iconArr = [
  {
      id: 1,
      className: 'banana-class',
      tags: ['']
  },
  {
      id: 2,
      className: 'apple-class',
      tags: ['']
  }
];

I would like to create a type that will cause an error if any other value other than banana-class or apple-class is written.

In array of strings i would use type iconStringType = typeof iconStringArr[number], but in my case i have an array of objects.

Thanks!

I tried using:

type iconType = typeof iconArr[number]['className'];

but it doesn't work - it allows any string value.

答案1

得分: 2

首先,你没有为你的 iconArr 数组设置类型,所以不管你的 Icon 接口如何定义,iconArr[number]['className'] 的类型都会被推断为 string

你可以通过明确设置 Icon[] 类型来轻松解决这个问题,如下所示:

const iconArr: Icon[] = [
    ...
];

然后,如果你想要对 className 中允许的字符串进行严格限制,你可以创建一个联合类型 'banana-class' | 'apple-class' 并在 Icon 接口中使用它,如下所示:

interface Icon {
    id: number,
    className: 'banana-class' | 'apple-class',
    tags: string[]
}

现在,你的 type iconType = typeof iconArr[number]['className'] 将评估为你创建的联合类型。

在评论中澄清后进行编辑:

如果你希望在运行时推断 Icon 类型,你可以这样做:

const iconArr = [
  {
      id: 1,
      className: 'banana-class' as const,
      tags: ['']
  },
  {
      id: 2,
      className: 'apple-class' as const,
      tags: ['']
  }
];

type Icon = typeof iconArr[number];

type iconType = typeof iconArr[number]['className'];

例如,使用 'apple-class' as const 声明告诉 TypeScript 推断“最狭窄的类型”,在你的情况下是 'banana-class' | 'apple-class'参考文档)。

英文:

First of all, you don't type you iconArr array so the type iconArr[number]['className'] is inferred as string regardless of your Icon interface.

This can easily be fixed by explicitly setting the Icon[] type like:

const iconArr: Icon[] = [
    ...
];

Then if you want to be strict on the allowed strings in your className you could create a union type 'banana-class' | 'apple-class' and use it in your Icon interface:

interface Icon {
    id: number,
    className: 'banana-class' | 'apple-class',
    tags: string[]
}

Now your type iconType = typeof iconArr[number]['className'] will evaluate to the union type you created.

Edit after clarification in comments:

If you want the Icon type inferred at runtime you can:

const iconArr = [
  {
      id: 1,
      className: 'banana-class' as const,
      tags: ['']
  },
  {
      id: 2,
      className: 'apple-class' as const,
      tags: ['']
  }
];

type Icon = typeof iconArr[number];

type iconType = typeof iconArr[number]['className'];

Defining e.g. 'apple-class' as const tells Typescript to infer the "narrowest type" which in your case is 'banana-class' | 'apple-class' (see docs)

huangapple
  • 本文由 发表于 2023年3月7日 19:40:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75661505.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定