You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从TypeScript常量提取分类与触发器名称的联合类型?

提取TypeScript常量中的分类与触发器名称联合类型

问题背景

我定义了如下TypeScript接口:

export interface GroupByCategoryAndTrigger {
  [key: string]: {
    label: string;
    name: string;
    triggers: {
      [key: string]: { name: string, label: string };
    }
  }
}

以及实现该接口的常量:

export const CATEGORIES: GroupByCategoryAndTrigger = {
  reservation: {
    name: 'Reservation' as const,
    label: 'Reservation',
    triggers: {
      created: { name: 'created', label: 'Reservation created' },
      confirmation: {
        name: 'confirmation' as const,
        label: 'Reservation confirmed',
      },
      edited: {
        name: 'edited' as const,
        label: 'Reservation edited',
      },
      canceled: {
        name: 'canceled' as const,
        label: 'Reservation cancelled',
      },
      reminder1: {
        name: 'reminder_1' as const,
        label: 'Reminder 1',
      },
      reminder2: {
        name: 'reminder_2' as const,
        label: 'Reminder 2',
      },
      reminder3: {
        name: 'reminder_3' as const,
        label: 'Reminder 3',
      },

      payment: {
        name: 'payment' as const,
        label: 'Awaiting Payment',
      },
      feedbackRequest: {
        name: 'feedback_request' as const,
        label: 'Feedback request',
      },
    },
  },
  queue: {
    name: 'Offline Waitlist' as const,
    label: 'Queue',
    triggers: {
      waitlistConfirmation: {
        name: 'waitlist_confirmation' as const,
        label: 'Waitlist confirmation',
      },
      tableConfirmation: { name: 'table_confirmation' as const, label: 'Table confirmation' },
    },
  },
};

我希望提取所有分类名称和触发器名称的联合类型,当前的写法如下:

export type CategoriesValues = typeof CATEGORIES[keyof GroupByCategoryAndTrigger]['name']; // 期望得到 "Reservation" | "Offline Waitlist"

export type TriggerValues =
  typeof CATEGORIES[keyof GroupByCategoryAndTrigger]['triggers'][string]['name']; // 期望得到 "confirmation" | "canceled" | ... 所有触发器名称

作为TypeScript新手,我想寻求正确的解决方案。

问题原因

问题出在你给CATEGORIES标注了GroupByCategoryAndTrigger接口,这会让TypeScript把所有name的类型统一当成接口里定义的string,直接丢掉了你用as const指定的具体字面量信息,所以拿不到预期的联合类型。

正确解决方案

方案1:移除接口标注,锁定字面量类型

如果你不需要修改这个常量,最简单的办法是去掉CATEGORIES的接口标注,换成as const来锁定所有字面量类型——这样TypeScript会完整保留每个name的具体字符串值:

export const CATEGORIES = {
  reservation: {
    name: 'Reservation' as const,
    label: 'Reservation',
    triggers: {
      created: { name: 'created', label: 'Reservation created' },
      confirmation: {
        name: 'confirmation' as const,
        label: 'Reservation confirmed',
      },
      edited: {
        name: 'edited' as const,
        label: 'Reservation edited',
      },
      canceled: {
        name: 'canceled' as const,
        label: 'Reservation cancelled',
      },
      reminder1: {
        name: 'reminder_1' as const,
        label: 'Reminder 1',
      },
      reminder2: {
        name: 'reminder_2' as const,
        label: 'Reminder 2',
      },
      reminder3: {
        name: 'reminder_3' as const,
        label: 'Reminder 3',
      },

      payment: {
        name: 'payment' as const,
        label: 'Awaiting Payment',
      },
      feedbackRequest: {
        name: 'feedback_request' as const,
        label: 'Feedback request',
      },
    },
  },
  queue: {
    name: 'Offline Waitlist' as const,
    label: 'Queue',
    triggers: {
      waitlistConfirmation: {
        name: 'waitlist_confirmation' as const,
        label: 'Waitlist confirmation',
      },
      tableConfirmation: { name: 'table_confirmation' as const, label: 'Table confirmation' },
    },
  },
} as const;

然后基于推导的类型提取联合类型:

// 提取分类名称联合类型
export type CategoriesValues = typeof CATEGORIES[keyof typeof CATEGORIES]['name'];
// 结果:"Reservation" | "Offline Waitlist"

// 提取触发器名称联合类型
export type TriggerValues = typeof CATEGORIES[keyof typeof CATEGORIES]['triggers'][keyof typeof CATEGORIES[keyof typeof CATEGORIES]['triggers']]['name'];
// 结果:"created" | "confirmation" | "edited" | "canceled" | "reminder_1" | "reminder_2" | "reminder_3" | "payment" | "feedback_request" | "waitlist_confirmation" | "table_confirmation"

方案2:保留接口约束,同时提取字面量类型

如果你需要确保CATEGORIES符合GroupByCategoryAndTrigger接口的结构,可以先让TypeScript推导常量的字面量类型,再做类型断言:

// 先定义接口
export interface GroupByCategoryAndTrigger {
  [key: string]: {
    label: string;
    name: string;
    triggers: {
      [key: string]: { name: string, label: string };
    }
  }
}

// 先定义原始常量,用as const锁定字面量类型
const rawCategories = {
  reservation: {
    name: 'Reservation' as const,
    label: 'Reservation',
    triggers: {
      created: { name: 'created', label: 'Reservation created' },
      confirmation: {
        name: 'confirmation' as const,
        label: 'Reservation confirmed',
      },
      edited: {
        name: 'edited' as const,
        label: 'Reservation edited',
      },
      canceled: {
        name: 'canceled' as const,
        label: 'Reservation cancelled',
      },
      reminder1: {
        name: 'reminder_1' as const,
        label: 'Reminder 1',
      },
      reminder2: {
        name: 'reminder_2' as const,
        label: 'Reminder 2',
      },
      reminder3: {
        name: 'reminder_3' as const,
        label: 'Reminder 3',
      },

      payment: {
        name: 'payment' as const,
        label: 'Awaiting Payment',
      },
      feedbackRequest: {
        name: 'feedback_request' as const,
        label: 'Feedback request',
      },
    },
  },
  queue: {
    name: 'Offline Waitlist' as const,
    label: 'Queue',
    triggers: {
      waitlistConfirmation: {
        name: 'waitlist_confirmation' as const,
        label: 'Waitlist confirmation',
      },
      tableConfirmation: { name: 'table_confirmation' as const, label: 'Table confirmation' },
    },
  },
} as const;

// 断言为接口类型,确保结构符合要求
export const CATEGORIES: GroupByCategoryAndTrigger = rawCategories;

// 基于rawCategories的推导类型提取联合类型
export type CategoriesValues = typeof rawCategories[keyof typeof rawCategories]['name'];
export type TriggerValues = typeof rawCategories[keyof typeof rawCategories]['triggers'][keyof typeof rawCategories[keyof typeof rawCategories]['triggers']]['name'];

这样既保留了接口的类型约束,又能提取到准确的字面量联合类型。

简化触发器类型提取(可选)

如果觉得触发器类型的写法太冗长,可以定义一个辅助类型来简化:

type CategoryTriggers<T> = T[keyof T]['triggers'];
export type TriggerValues = CategoryTriggers<typeof rawCategories>[keyof CategoryTriggers<typeof rawCategories>]['name'];

内容的提问来源于stack exchange,提问作者Murtaza Hussain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 07:55:38