React多语言标签的TypeScript类型优化及Context报错解决
React多语言切换转TypeScript的类型优化与Context类型错误问题
问题背景
原本在ReactJS应用中使用labels.js对象实现多语言切换,代码如下:
export const labelsENG = { navSeries: 'shows', navHome: 'home', navVideo: 'video', navGames: 'games', navCurrent: 'current', navCatchUp: 'shame pile', navCommingSoon: 'comming soon', navFinished: 'finished', formModalHeader: 'Add new Poster', modalNoWiki: 'No wiki for ', modalCloseButton: 'CLOSE MODAL', modalReleased: 'Relased ', modalSeenAt: 'You seen it ', itemPart: 'Part ', itemSeason: 'Season ', footerCopyRights: '© 2022 Listownik by Kuba', footerHere: 'Footer here', error404: 'Error 404 Page Not Happy', errorDescribtion: `It's working anyway`, posterText: 'Some text', shelfSeen: 'Seen' };
现在要转换为TypeScript,想找比逐个声明字符串属性的接口更高效优雅的类型声明方式,当前使用的接口:
export interface LabelsInterface { navSeries: string; navHome: string; navVideo: string; navGames: string; navCurrent: string; navCatchUp: string; navCommingSoon: string; navFinished: string; modalNoWiki: string; modalCloseButton: string; modalReleased: string; modalSeenAt: string; itemPart: string; itemSeason: string; footerCopyRights: string; footerHere: string; error404: string; errorDescribtion: string; posterText: string; shelfSeen: string; }
补充问题:Context类型错误
子组件中为Context的labels声明类型时出错,代码:
const { labels }: LabelsInterface = useContext(LanguageContext);
labels的值为labelsENG或其他语言的labels对象,相关Context代码:
type Language = { lang: string; setLang: Dispatch<SetStateAction<Language>>; }; const initialState: Language = { lang: languageLabel.eng, setLang: (): void => {} }; const labelInitialState: {} = { labels: {}, setLang: (): void => {} }; export const LanguageContext = createContext(labelInitialState); const DataProvider = () => { const [lang, setLang] = useState<Language>(initialState); const isLanguageEng: boolean = (lang as any) === 'ENG'; const labels = isLanguageEng ? labelsENG : labelsPL; return ( <LanguageContext.Provider value={{ labels, setLang }}> <RouteProvider /> </LanguageContext.Provider> ); };
报错信息
TS2740: Type '{}' is missing the following properties from type '{ navSeries: string; navHome: string; navVideo: string; navGames: string; navCurrent: string; navCatchUp: string; navCommingSoon: string; navFinished: string; formModalHeader: string; modalNoWiki: string; ... 10 more ...; shelfSeen: string; }': navSeries, navHome, navVideo, navGames, and 17 more. TS2339: Property 'labels' does not exist on type '{ navSeries: string; navHome: string; navVideo: string; navGames: string; navCurrent: string; navCatchUp: string; navCommingSoon: string; navFinished: string; formModalHeader: string; modalNoWiki: string; ... 10 more ...; shelfSeen: string; }'.
解决方案
1. 更优雅的Labels类型声明
不用手动维护接口,直接用typeof基于现有labelsENG自动推导类型,结构更新时类型会同步变化:
// 基于labelsENG自动生成类型 export type LabelsType = typeof labelsENG; // 其他语言的labels对象直接用这个类型约束,TS会自动校验所有属性是否齐全 export const labelsPL: LabelsType = { navSeries: '节目', navHome: '主页', // 填充剩余翻译属性 };
2. 修复Context类型错误
问题核心是Context的初始状态类型、state类型和使用时的类型不匹配,按以下步骤修正:
第一步:定义Context值的正确类型
import { Dispatch, SetStateAction } from 'react'; import { LabelsType } from './path-to-your-labels-file'; // 明确Context传递的值的类型 type LanguageContextValue = { labels: LabelsType; setLang: Dispatch<SetStateAction<string>>; };
第二步:修正初始状态与Context创建
// 初始状态要符合LanguageContextValue类型,空对象占位时加类型断言 const labelInitialState: LanguageContextValue = { labels: {} as LabelsType, setLang: () => {}, }; export const LanguageContext = createContext<LanguageContextValue>(labelInitialState);
第三步:修正DataProvider中的state类型
原代码中useState的类型错误,lang应该是字符串而非自定义的Language对象:
const DataProvider = () => { // 修正state类型,lang是字符串类型 const [lang, setLang] = useState<string>(languageLabel.eng); // 不需要any断言,直接判断字符串 const isLanguageEng = lang === 'ENG'; const labels = isLanguageEng ? labelsENG : labelsPL; return ( <LanguageContext.Provider value={{ labels, setLang }}> <RouteProvider /> </LanguageContext.Provider> ); };
第四步:子组件中正确使用Context
// 直接解构Context值,无需手动指定类型,TS会自动推导 const { labels } = useContext(LanguageContext); // 之后可直接使用labels.navSeries等属性,类型自动校验
内容的提问来源于stack exchange,提问作者Voote
相关产品推荐
相关产品推荐

