如何在TypeScript泛型中正确处理对象键以适配TSX组件
TSX泛型Options组件类型修正方案
问题说明
在TSX开发中编写泛型组件时遇到类型组合问题:需要实现一个Options组件,要求:
- 接收
display参数,该参数必须是泛型类型的属性名(字符串类型) - 泛型类型需继承
{id: string},确保传入的数组项(如PETS或USERS类型)包含id属性 - 组件遍历数组渲染option标签,显示
display指定的属性值,value绑定id
原代码问题
原组件的泛型参数U未添加约束,导致display的类型无法和Y的键关联,访问val[display]时会出现类型错误,即使使用类型断言也不够严谨。
原代码:
import React from "react"; interface IOptions<T, K extends keyof T> { display: K; values: T[]; } const Options = <Y extends {id: string}, U>({values, display}: IOptions<Y, U>) => { return ( <> {values.map((val: Y, index: number) => ( <option key={index} value={val.id}>{val[display]}</option> ))} </> ); }; export default Options;
尝试的不严谨写法:
<option key={index} value={val.id}>{val[display as keyof Y]}</option>
修正方案
给组件的泛型参数U添加extends keyof Y的约束,让display的类型明确为Y的键,TypeScript就能正确推断val[display]的类型,无需额外断言。
修正后的代码:
import React from "react"; interface IOptions<T, K extends keyof T> { display: K; values: T[]; } // 给U添加extends keyof Y约束,确保display是Y的合法属性名 const Options = <Y extends {id: string}, U extends keyof Y>({values, display}: IOptions<Y, U>) => { return ( <> {values.map((val, index) => ( <option key={index} value={val.id}> {val[display]} </option> ))} </> ); }; export default Options;
简化写法(可选)
也可以直接在组件props中定义泛型,无需单独的IOptions接口,让代码更简洁:
import React from "react"; const Options = <Y extends {id: string}, K extends keyof Y>({ values, display, }: { values: Y[]; display: K; }) => { return ( <> {values.map((val, index) => ( <option key={index} value={val.id}> {val[display]} </option> ))} </> ); }; export default Options;
使用示例
假设定义以下类型:
type Pet = { id: string; name: string; breed: string; }; type User = { id: string; username: string; email: string; };
使用组件时,TypeScript会自动推断类型,且display只能传入对应类型的合法属性名:
// 渲染宠物选项,display仅支持name/breed/id <Options values={pets} display="name" /> // 渲染用户选项,display仅支持username/email/id <Options values={users} display="username" />
内容的提问来源于stack exchange,提问作者aRtoo
相关产品推荐
相关产品推荐

