網站搜尋

Typescript 的列舉子集


在 Typescript 中,我有一個像這樣的 enum

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

我想要像這樣創建這個枚舉的子集,但似乎無法做到

enum JapaneseCars {
    CarBrands.Toyota
}

或使用子集創建一個物件

const JapaneseCars = {
    Carbrands.Toyota
}

有沒有辦法我可以創建一個物件或列舉,使用來自另一個已存在列舉的值?

我無法將 CarBrands 列舉改為其他資料類型

答案#1

你可以創建一個 type 和 const 的組合,它的行為就像另一個 enum 的子集。

缺點:這個解決方案強制要求你讓任何 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 的未知值映射到類型為 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,可以展示所有這些代碼並實時進行類型檢查

答案#2

我覺得你在找的東西可能像這個 -

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

type JapaneseCars = CarBrands.Toyota;

const car: JapaneseCars;