在泛型内使用索引访问类型时避免联合类型推断
解决TypeScript中泛型接口根据key值推断render函数签名的问题
你的核心问题是联合类型无法关联key和render的类型关系,导致指定key时,render参数被推断为所有属性类型的联合。可以通过分布式联合类型实现key与render参数类型的绑定,让TypeScript根据具体key值精确推断类型。
修正后的类型定义
import type { JSX } from "react"; interface BaseColumnDefinition<T extends Record<string, any>> { label?: string; } // 无key的列定义:render接收完整的T对象 interface KeylessColumnDefinition<T extends Record<string, any>> extends BaseColumnDefinition<T> { key?: undefined; render: (value: T) => JSX.Element; } // 针对单个key的有key列定义:泛型K绑定具体的key,render参数对应T[K] type KeyedColumnDefinition<T extends Record<string, any>, K extends keyof T> = BaseColumnDefinition<T> & { key: K; render: (value: T[K]) => JSX.Element; }; // 生成包含所有key类型的联合类型,再合并无key类型 type ColumnDefinition<T extends Record<string, any>> = | KeylessColumnDefinition<T> | { [K in keyof T]: KeyedColumnDefinition<T, K> }[keyof T];
测试验证
type TestData = { name: string; id: string; value: number }; // 无key场景:render参数正确推断为完整TestData类型 const definitionWithoutKey: ColumnDefinition<TestData> = { label: "Name", render: (value) => <></>, }; // 有key场景:key为"value"时,render参数自动推断为number类型 const definitionWithKey: ColumnDefinition<TestData> = { label: "Name", key: "value", render: (value) => <></>, }; // 类型校验生效:key为"name"时,render参数传number会报错 const definitionWithWrongType: ColumnDefinition<TestData> = { label: "Name", key: "name", render: (value: number) => <></>, // ❌ 类型错误:value应为string };
原理说明
- 原代码中
KeyedColumnDefinition用T[this["key"]]无法在联合类型中关联key和render的类型,因为TypeScript会将联合类型的成员视为独立个体,无法跟踪跨成员的关联。 - 新方案通过映射类型
{ [K in keyof T]: KeyedColumnDefinition<T, K> }[keyof T],为每个key生成单独的类型分支,最终形成一个包含所有key对应类型的联合。当TypeScript匹配到具体的key值时,会自动选中对应的分支,从而精确推断render的参数类型。
内容的提问来源于stack exchange,提问作者Metallicity
相关产品推荐
相关产品推荐

