TypeScript中以数组值作为关联属性联合类型的问题
实现方案
可以实现,核心要解决两个类型推断问题:一是传入自定义perPageVariants时,TS默认会把数组字面量拓宽为number[],导致联合类型校验失效;二是as const生成的只读元组和可变数组类型约束不兼容。
完整可运行代码
// 抽离全局默认配置,保留as const保证精确字面量类型 const defaultPerPageVariants = [10, 25, 50, 100, 200] as const; type PaginationProps<P extends readonly number[]> = { // 可变元组写法[...P]触发字面量精确推断,避免数组被拓宽为number[] perPageVariants?: [...P]; perPageDefault?: P[number]; }; const Pagination = <P extends readonly number[] = typeof defaultPerPageVariants>( props: PaginationProps<P> ) => { const { perPageVariants = defaultPerPageVariants as [...P], perPageDefault = perPageVariants[0], } = props; return null; };
关键逻辑说明
- 泛型约束从
number[]改为readonly number[]:TS中readonly number[]是所有数字数组(可变/只读)的父类型,既兼容用户传入的普通数组,也兼容as const生成的只读默认配置,解决只读类型赋值报错的问题。 perPageVariants类型写为[...P]:可变元组展开语法会提示TS不要将传入的数组字面量拓宽为宽泛的number[]类型,而是精确推断为传入值的字面量元组,这样P[number]就能拿到传入选项的精确数字联合类型,实现动态校验。- 默认值处的
as [...P]类型断言是安全的:默认配置本身符合泛型P的类型约束,仅用于消弭只读元组赋值给可变元组位置的类型提示,不会影响运行时逻辑。
校验效果验证
// ✅ 合法:不传自定义选项时,perPageDefault仅允许默认值列表内的数字 <Pagination perPageDefault={10} /> // ❌ 类型错误:1000不在默认选项列表中 <Pagination perPageDefault={1000} /> // ✅ 合法:自定义选项下,perPageDefault允许传入自定义列表内的值 <Pagination perPageVariants={[123, 456]} perPageDefault={123} /> // ❌ 类型错误:100不在自定义选项[123,456]中,符合预期 <Pagination perPageVariants={[123, 456]} perPageDefault={100} />
内容的提问来源于stack exchange,提问作者Alexander Krupko
相关产品推荐
相关产品推荐

