一个只能包含特定列表元素的数组的 Typescript 类型。

4

我想要声明一个类型的数组,该数组最多只能包含以下字符串之一:'first''second''third'

这个数组的一些有效示例:

  • []
  • [ 'first' ]
  • [ 'first', 'second' ]
  • [ 'first', 'second', 'third' ]
  • [ 'first', 'third' ]
  • [ 'second', 'third' ]

一些无效的数组:

  • [ 'other-value' ] // 不允许其他值
  • [ 'first', 'first' ] // 不允许重复

我写的类型:

export enum MyOptions {
  first = 'first',
  second = 'second',
  third = 'third'
}

export type MyType = {
  name: string;
  email: string;
  listings: {
   MyOptions;
  }[];
};

它有一个警告,指出成员'MyOptions'隐式具有'any'类型,但更好的类型可以从使用中推断出来

所以如果将其更改为:

export type MyType = {
  name: string;
  email: string;
  listings: {
   options: MyOptions;
  }[];
};

现在没有警告,但它有那个额外的options值,我认为不必添加。

有什么方法可以解决这个问题吗?

4个回答

6
您可以使用Set数据结构。
export type Options = 'first' | 'second' | 'third'
export type Listing = Set<Options>

export type MyType = {
    name: string;
    email: string;
    listings: Listing;
};

const myType = {
  name: 'name',
  email: 'email',
  listing: new Set(['first', 'second'])
}

那么您将确信在您的列表中没有重复的选项。 注意:实际上,您可以传递重复的选项,但Set会忽略它们。


2
我认为你有一组多余的括号是不必要的。
export type MyType = {
  name: string;
  email: string;
  listings: {
   MyOptions;
  }[];
};

应该被更改为

export type MyType = {
  name: string;
  email: string;
  listings: MyOptions[];
};

你还有一个更简洁的选择:使用字符串字面类型:
export type MyType = {
  name: string;
  email: string;
  listings: ('first' | 'second' | 'third')[];
};

看起来你的答案接受重复项 ([ 'first', 'first' ]),这是不应该的。我在问题描述中已将其添加为无效数组,也许之前没有表述清楚。 - Leo Messi

0

应该是这样的:

export type MyType = {
    name: string;
    email: string;
    listings: MyOptions[];
};

假设您有一个名为xMyType变量,那么要将新值推送到listings成员,您可以执行x.listings.push(MyOptions.first)


0
第二种解决方案意味着您现在有一个可能看起来像以下对象的对象:

const exampleObject = {
  name: 'Ralf';
  email: 'XXX@XX.xx';
  listings: {
   options: 'first';
  }[];
};

这并不是你的本意,因为你不能在那里有一个['first','second'],而只能有一个值。
如果您使用样式
listings: MyOptions[];

然后它还允许内容为['first', 'first']

据我所知,通过typescript类型,没有办法仅限制可能的值不仅通过其内容,而且还通过其数量(最多只有每个值的一个)。

因此,您将不得不创建自己的逻辑。

例如,拥有一个小型业务对象

class Options {
  private _values: MyOptions[] = [];

  addOption(option:MyOption){
    if(this._values.some(option)){
      return; // or throw an error, depends on your usecase
    }
    this.values.concat(option);
  }

  get options():MyOptions{
    return this._values;
  }
}

现在你可以拥有你的包装类型:

export type MyType = {
  name: string;
  email: string;
  listings: Options
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接