如何正确将TypeScript枚举映射为自定义PickerOption对象?
问题
我定义了一个TypeScript字符串枚举:
export enum LanguagesEnglish { 'enUS'= 'English', 'zhHant'= 'Mandarin, Traditional', };
想要用它生成选择器组件的选项,组件要求的选项类型是:
type pickerOption = { code: string, label: string, };
我尝试修改类型定义并编写生成函数:
type pickerOption = { code: keyof LanguagesEnglish, label: LanguagesEnglish, }; function generateOption(key: keyof LanguagesEnglish): pickerOption { return { code: key, label: LanguagesEnglish[key], } }
最后用Object.keys()映射生成数组时:
const options = Object.keys(LanguagesEnglish).map(generateOption);
出现了类型错误:
Element implicitly has an 'any' type because expression of type 'number | unique symbol | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | ... 35 more ... | "at"' can't be used to index type 'typeof LanguagesEnglish'. No index signature with a parameter of type 'number' was found on type 'typeof LanguagesEnglish'. (lsp)
明明指定了key的类型是keyof LanguagesEnglish,为什么还会报错?正确的枚举映射方式是什么?
原因
Object.keys()的类型缺陷:TypeScript中Object.keys()的返回值被定义为string[],而非枚举的具体键类型keyof LanguagesEnglish,直接传给generateOption会触发类型不匹配。- 字符串枚举的双向映射:TypeScript编译字符串枚举时,会生成同时包含
键→值和值→键的双向映射对象,Object.keys()会把数值形式的反向键也包含进去,进一步导致类型错误。
正确解决方案
方案一:过滤无效键+类型断言
先过滤掉双向映射产生的数值键,再对Object.keys()的结果做类型断言,确保传入的是合法枚举键:
export enum LanguagesEnglish { 'enUS'= 'English', 'zhHant'= 'Mandarin, Traditional', }; type pickerOption = { code: keyof typeof LanguagesEnglish, label: LanguagesEnglish, }; function generateOption(key: keyof typeof LanguagesEnglish): pickerOption { return { code: key, label: LanguagesEnglish[key], }; } // 过滤数值键,同时断言类型为枚举键 const options = Object.keys(LanguagesEnglish) .filter(key => isNaN(Number(key))) .map(key => generateOption(key as keyof typeof LanguagesEnglish));
方案二:直接用Object.entries()处理键值对
跳过单独的生成函数,直接遍历枚举的键值对并过滤无效项:
export enum LanguagesEnglish { 'enUS'= 'English', 'zhHant'= 'Mandarin, Traditional', }; type pickerOption = { code: string, label: string, }; const options: pickerOption[] = Object.entries(LanguagesEnglish) .filter(([key]) => isNaN(Number(key))) .map(([code, label]) => ({ code, label }));
方案三:预定义合法键数组(类型最安全)
手动定义枚举的合法键数组,完全避免类型断言,同时保证类型严格:
export enum LanguagesEnglish { 'enUS'= 'English', 'zhHant'= 'Mandarin, Traditional', }; // 定义只读的枚举键数组 const languageKeys = ['enUS', 'zhHant'] as const; // 推导键的类型 type LanguageKey = typeof languageKeys[number]; type pickerOption = { code: LanguageKey, label: LanguagesEnglish, }; // 直接映射生成选项,类型完全安全 const options = languageKeys.map(key => ({ code: key, label: LanguagesEnglish[key], }));
内容的提问来源于stack exchange,提问作者Caleb Jay
相关产品推荐
相关产品推荐

