TypeScript中如何为React状态指定仅含单个TLang键的对象类型?
React useState类型定义优化:仅保留单个语言键
问题代码
type TLang = 'tur' | 'eng'; const [filterState, setFilterState] = useState<{ [key in TLang]: string | null; }>(null); const inputChangeHadnler = (type: TLang): React.ChangeEventHandler<HTMLInputElement> => (event) => { setFilterState({ [type]: event.target.value }); }; return <input onChange={inputChangeHadnler('tur')}></input>
报错信息
Argument of type '{ [x: string]: string; }' is not assignable to parameter of type 'SetStateAction<{ tur: string; eng: string; }>'.
Type '{ [x: string]: string; }' is missing the following properties from type '{ tur: string; eng: string; }': tur, engts(2345)
当前filterState的类型要求必须同时包含tur和eng两个属性,但实际需求是让它仅包含TLang中的单个键(要么tur,要么eng,或者null)。手动枚举{ tur: string | null } | { eng: string | null} | null的写法在语言数量增多时会变得繁琐,需要更通用的方案。
解决方案
可以用TypeScript的映射类型+索引访问生成通用的单键对象联合类型,无需手动枚举每个语言:
- 先定义通用的单键对象类型与最终状态类型:
// 单个语言键对应的对象类型 type SingleLangFilter<K extends string> = { [key in K]: string | null }; // 自动生成所有单键对象的联合类型,再加上null type FilterStateType = { [K in TLang]: SingleLangFilter<K> }[TLang] | null;
- 修改useState的类型定义:
const [filterState, setFilterState] = useState<FilterStateType>(null);
- 调整事件处理器,让TS正确推断类型:
const inputChangeHadnler = <K extends TLang>(type: K): React.ChangeEventHandler<HTMLInputElement> => (event) => { setFilterState({ [type]: event.target.value } as SingleLangFilter<K>); };
修改后的完整代码
import { useState } from 'react'; type TLang = 'tur' | 'eng'; type SingleLangFilter<K extends string> = { [key in K]: string | null }; type FilterStateType = { [K in TLang]: SingleLangFilter<K> }[TLang] | null; const MyComponent = () => { const [filterState, setFilterState] = useState<FilterStateType>(null); const inputChangeHadnler = <K extends TLang>(type: K): React.ChangeEventHandler<HTMLInputElement> => (event) => { setFilterState({ [type]: event.target.value } as SingleLangFilter<K>); }; return <input onChange={inputChangeHadnler('tur')} />; }; export default MyComponent;
这样无论TLang新增多少个语言值(比如加上'spa'),FilterStateType都会自动生成对应的单键对象联合类型,完全无需手动修改类型定义。
内容的提问来源于stack exchange,提问作者Roman Poludnev
相关产品推荐
相关产品推荐

