枚举的 typescript 子集

a0x5cqrl  于 2023-03-13  发布在  TypeScript
关注(0)|答案(5)|浏览(135)

在Typescript中,我有一个枚举

export enum CarBrands {
   Toyota = "TOYOTA"
   Ford = "FORD"
   .....
}

我想创建此枚举的一个子集,如下所示,但似乎无法实现

enum JapaneseCars {
    CarBrands.Toyota
}

或创建一个具有子集的对象

const JapaneseCars = {
    Carbrands.Toyota
}

有没有什么方法可以创建一个对象或枚举,使用另一个现有枚举的值?
我无法将CarBrands枚举更改为其他数据类型

czq61nw1

czq61nw11#

可以创建typeconst组合,其行为类似于作为另一个枚举的子集的枚举。

缺点:这个解决方案强迫您让任何enum的键与它们的值匹配(或者我还没有找到处理这种情况的解决方案)

// Given an enum
export enum CarBrand {
  TOYOTA = 'TOYOTA',
  FORD = 'FORD',
  PEUGEOT = 'PEUGEOT',
  RENAULT = 'RENAULT'
}

// We can create the type of the subset
export type FrenchCarBrand = Extract<CarBrand, CarBrand.PEUGEOT | CarBrand.RENAULT>;

// And the const that goes with it
export const FrenchCarBrand = {
  [CarBrand.PEUGEOT]: CarBrand.PEUGEOT,
  [CarBrand.RENAULT]: CarBrand.RENAULT
} as const;

// With that you can :

// assign a CarBrand to a FrenchCarBrand ...
const a: FrenchCarBrand = CarBrand.RENAULT;

// ... as long as the CarBrand is in the type
const a_invalid: FrenchCarBrand = CarBrand.TOYOTA; // Type 'CarBrand.TOYOTA' is not assignable to type 'FrenchCarBrand'.

// assign a FrenchCarBrand to a CarBrand ...
const b: CarBrand = FrenchCarBrand.PEUGEOT;

// ... as long as the key exists
const b_invalid: CarBrand = FrenchCarBrand.TOYOTA; // Property 'TOYOTA' does not exist on type 'Readonly<Record<FrenchCarBrand, FrenchCarBrand>>'

// You cannot reassign the value of a FrenchCarBrand ...
FrenchCarBrand.PEUGEOT = CarBrand.RENAULT; // Cannot assign to 'PEUGEOT' because it is a read-only property.

// ... just like you cannot reassign the value of an enum
CarBrand.TOYOTA = 'MAZDA'; // Cannot assign to 'TOYOTA' because it is a read-only property.

如果你想把CarBrand类型的未知值Map到FrenchCarBrand类型的值,它将无法工作:

declare const brand: CarBrand;
const frenchBrand: FrenchCarBrand = brand; // Type 'CarBrand' is not assignable to type 'FrenchCarBrand'

// You can use the `as` keyword but it will hide bugs, so I do not recommend at all.
const frenchBrandNoError: FrenchCarBrand = brand as FrenchCarBrand; // No error, but a possible bug in your application.

为此,您需要一个类型保护:

export const isFrenchCarBrand = (brand: CarBrand): brand is FrenchCarBrand => {
  return brand in FrenchCarBrand;
}

它将允许您决定遇到不需要的值时应采取的操作

if (isFrenchCarBrand(brand)) {
  // You can safely assume that `brand` is a `FrenchCarBrand`
} else {
  // `brand` is definitely not a `FrenchCarBrand`
}

我制作了一个TypeScript Playground,展示了所有这些代码,并在其中执行了类型检查

ljo96ir5

ljo96ir52#

我觉得你在找这样的东西-

export enum CarBrands {
  Toyota = "TOYOTA",
  Ford = "FORD"
}

type JapaneseCars = CarBrands.Toyota;

const car: JapaneseCars;
vc6uscn9

vc6uscn93#

一个可能的解决方法是使用Extract〈Type,Union〉创建一个具有所需Enum值的类型,而不需要创建一个Enum键等于其值的常量。
当然,它不会创建一个新的Enum,但是您将能够键入常量或属性,并且它将确保从原始Enum中提取的值的类型。

enum CarBrands {
  Chevrolet = 'CHEVROLET',
  Honda = 'HONDA',
  Toyota = 'TOYOTA',
  Ford = 'FORD',
  // etc...
}

type JapaneseBrands = Extract<
  CarBrands,
  | CarBrands.Honda
  | CarBrands.Toyota
  // etc...
>;

const goodJapaneseBrands: JapaneseBrands = CarBrands.Honda; // OK
const badJapaneseBrands: JapaneseBrands = CarBrands.Ford; // ERROR
wnrlj8wa

wnrlj8wa4#

我认为您需要创建一个带有可选值的索引对象:

enum CarBrand {
  TOYOTA = "TOYOTA",
  FORD = "FORD"
}

type CarsSubset = {
  [key in CarBrand]?: boolean
}

const JapaneseCars: CarsSubset  = {
  TOYOTA: true,
}

对于这个特定的例子,只使用Set<CarBrand>可能会更清楚:

const JapaneseCars = new Set<CarBrand>([CarBrand.TOYOTA]);
1dkrff03

1dkrff035#

你可以为每一个枚举成员创建一个变量,如果你有很多枚举成员的话,这会很乏味,但是它看起来像这样。

export enum CarBrands {
    Toyota = "TOYOTA",
    Ford = "FORD"
}

const Toyota = CarBrands.Toyota;
console.log("The Supra is made by", Toyota)

或者你可以用一个简单的方法

class JapaneseCar {
    make: string;
    // Additional Methods / Properties

    setMake(brand:CarBrands){
        this.make = brand;
    }
}

const ToyotaSupra = new JapaneseCar();
ToyotaSupra.setMake(CarBrands.Toyota);
console.log(ToyotaSupra.make)

相关问题