React泛型Hook中TypeScript转换对象为SelectOption时类型错误求助
解决TypeScript中
T[string]无法赋值给string | number的类型错误 错误原因
你编写的useOptions Hook中,泛型T仅被约束为object,但T的属性类型可以是任意类型(比如boolean、复杂对象等)。而SelectOption要求label和value必须是string | number,TypeScript无法确保item[labelKey]或item[valueKey]的类型符合要求,因此抛出类型不匹配的错误。
解决方案
以下两种方案可解决该问题,根据你的业务场景选择:
方案1:通过泛型约束严格限制属性类型
直接在泛型定义中约束T的labelKey和valueKey对应的属性必须是string | number,从源头避免类型不匹配:
export interface SelectOption { value: number | string; label: number | string; } const useOptions = < T extends Record<L, string | number> & Record<V, string | number>, L extends keyof T, V extends keyof T >(props: { items: T[]; labelKey: L; valueKey: V }) => { const { items, labelKey, valueKey } = props; const options = useMemo<SelectOption[]>(() => { return items.map((item) => ({ label: item[labelKey], value: item[valueKey], })); }, [items, labelKey, valueKey]); // 补充labelKey和valueKey作为依赖项 return options; }; export default useOptions;
优点:在调用Hook时就会校验传入的items是否符合类型要求,提前暴露错误,避免运行时问题。
方案2:强制转换属性类型为string/number
如果无法约束T的属性类型,或者需要兼容其他类型的属性,可以在映射时将属性值转换为string或number:
export interface SelectOption { value: number | string; label: number | string; } interface IProps<T> { items: T[]; labelKey: keyof T; valueKey: keyof T; } const useOptions = <T extends object>(props: IProps<T>) => { const { items, labelKey, valueKey } = props; const options = useMemo<SelectOption[]>(() => { return items.map((item) => ({ // 使用String()转换为字符串,也可根据需求用Number()转换为数字 label: String(item[labelKey]), value: String(item[valueKey]), })); }, [items, labelKey, valueKey]); return options; }; export default useOptions;
注意:转换时要确保属性值可以被正常转换为目标类型(比如boolean转string会得到"true"/"false",符合要求;但复杂对象转string会得到"[object Object]",需要根据业务判断是否接受)。
额外修复:补充useMemo依赖项
你原来的代码中useMemo的依赖项缺少labelKey和valueKey,当这两个参数变化时,options不会重新计算,这会导致Bug,上述两个方案都已补充了完整的依赖项。
内容的提问来源于stack exchange,提问作者uguremirmustafa
相关产品推荐
相关产品推荐

