TypeScript中如何定义固定条目数、键值均为number类型的对象类型
TypeScript 固定条目数number键值对象类型实现
原写法存在两个核心问题:
- TypeScript同一类型下,
number/string类型的索引签名仅允许定义1次,重复定义会直接抛出语法错误 - 索引签名的作用是约束所有匹配该键类型的属性的值类型,和对象包含的键数量无关,哪怕仅写1次
[key: number]: number,也会允许对象存在任意多个number类型的键,无法满足固定2个条目的要求。
以下是不同场景下的正确实现:
已知固定队伍ID场景
如果参赛的两个队伍ID是固定可预知的,不需要动态键,直接定义明确的对象结构即可,无需使用索引签名:
// 示例:参赛队伍固定为ID 1001、1002 type MatchResult = { 1001: number; 1002: number; } // 校验通过 const finalResult: MatchResult = { 1001: 3, 1002: 1 }
需类型层面强制约束2个键值对场景
如果队伍ID为动态number类型,且需要在类型检查阶段就强制对象只能有2个键、值均为number,可通过泛型结合键集合长度校验实现:
type ExactTwoNumEntries<T> = T extends Record<keyof T, number> ? keyof T extends number ? [keyof T] extends [infer K extends PropertyKey] ? { 0: unknown, 1: unknown }[Extract<K, number>] extends never ? never : [K, K, K] extends [K, K, infer Third] ? Third extends K ? never : T : never : never : never : never; // 用法:声明变量时传入对象结构做校验 const validResult: ExactTwoNumEntries<{2: 3, 5: 1}> = {2:3, 5:1}; // 校验通过 const lackEntry: ExactTwoNumEntries<{2:3}> = {2:3}; // 类型报错,条目数量不足 const tooManyEntries: ExactTwoNumEntries<{2:3, 5:1, 7:0}> = {2:3,5:1,7:0}; // 类型报错,条目超出2个 const wrongValueType: ExactTwoNumEntries<{2: string, 5:1}> = {2:"3",5:1}; // 类型报错,值不是number类型
实际业务开发推荐方案
绝大多数比赛结果场景下,队伍ID都是接口动态返回的,类型阶段无法预知具体ID值,不需要过度追求类型层面的精确数量约束,直接使用单个number索引签名定义类型,将固定2个条目的校验放在运行时逻辑处理即可,实现成本最低且完全覆盖业务需求:
type MatchResult = Record<number, number>; // 运行时类型守卫,校验是否为符合要求的两队比赛结果 function isValidMatchResult(result: unknown): result is MatchResult { if (typeof result !== 'object' || result === null) return false; const entries = Object.entries(result as object); if (entries.length !== 2) return false; return entries.every(([key, value]) => !Number.isNaN(Number(key)) && typeof value === 'number'); }
内容的提问来源于stack exchange,提问作者vlio20
相关产品推荐
相关产品推荐

