You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TypeScript定义含description与数字类型ID属性的超类型?

TypeScript 定义含动态ID属性与固定description的超类型

问题场景

我们需要为一组键值结构的子类型定义超类型,后端返回的结构未使用key和value,而是采用somethingId+description的形式,示例如下:

{
  somethingId: 1,
  description: "Entity description"
}

其中仅something部分会随实体类型变化,要求该超类型必须满足:

  • 包含一个string类型的description属性
  • 包含且仅包含一个number类型的动态命名属性(命名以Id结尾)

原有尝试的问题

之前的定义方式无法满足严格类型约束:

// 错误:TypeScript会强制所有属性(包括description)为number类型
type MyType = {
  [k: string]: number;
  description: string;
}

// 不足:所有属性都允许是number或string,无法保证动态属性仅为number、且只有一个动态属性
type MyType = {
  [k: string]: number | string;
  description: string;
}

解决方案

方案1:泛型指定动态属性名(推荐,类型最严格)

通过泛型明确动态ID属性的名称,既保证类型安全,又支持不同实体的ID命名:

// 泛型T指定动态ID属性的名称
type EntityType<T extends string> = {
  [K in T]: number;
} & {
  description: string;
};

// 针对不同实体创建子类型
type SomethingEntity = EntityType<'somethingId'>;
type UserEntity = EntityType<'userId'>;

// 合法示例
const validSomething: SomethingEntity = {
  somethingId: 123,
  description: "这是一个实体描述"
};

// 非法示例(TypeScript会报错)
// const invalidSomething: SomethingEntity = {
//   somethingId: "123", // 类型应为number
//   description: "错误示例"
// };

方案2:匹配任意以Id结尾的属性(无需固定ID名称)

如果不需要指定具体的ID属性名,仅要求存在唯一的xxxId格式的number属性,可通过映射类型结合条件类型实现:

type IdEntity = {
  // 仅保留以Id结尾的属性,类型为number
  [K in string as K extends `${string}Id` ? K : never]: number;
} & {
  description: string;
} & {
  // 确保没有多余属性
  [key: string]: never;
};

// 合法示例
const validEntity: IdEntity = {
  orderId: 456,
  description: "订单描述"
};

// 非法示例(TypeScript会报错)
// const invalidEntity: IdEntity = {
//   orderId: 456,
//   userId: 789, // 存在多个Id属性
//   description: "错误示例"
// };

方案3:类型断言(临时兼容场景,不推荐)

如果需要快速兼容现有结构,可通过类型守卫做运行时检查,不过类型约束较弱:

type BaseEntity = {
  description: string;
};

// 类型守卫:验证对象符合要求
function isEntity<T extends BaseEntity>(obj: T): obj is T & Record<string, number> {
  const nonDescKeys = Object.keys(obj).filter(key => key !== 'description');
  return nonDescKeys.length === 1 && typeof obj[nonDescKeys[0] as keyof T] === 'number';
}

// 使用示例
const testObj = { productId: 789, description: "产品描述" };
if (isEntity(testObj)) {
  // 此处testObj的类型被正确推断
  console.log(testObj.productId, testObj.description);
}

内容的提问来源于stack exchange,提问作者César Rodriguez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 09:20:22