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

如何在不继承类的情况下正确推断类属性的类型?

问题解决:TypeScript保留类属性原始类型的方法

问题场景

以下代码中,getSchema函数返回的类型被TypeScript推断为每个属性都是所有属性类型的联合,但期望每个属性保留其原始具体类型:

class XClass {
  x = "x";
  y = 11;
  b = true;
}
let xObj = new XClass();
function getSchema<T extends XClass>(instance: T): Record<keyof T, T[keyof T]> {
  const returnObj = {} as Record<keyof T, T[keyof T]>;
  for (const key in instance) {
    returnObj[key] = instance[key];
  }
  return returnObj;
}
let schema = getSchema(xObj);
type X = typeof schema;

// 当前推断的类型:
// type X = {
//   x: string | number | boolean;
//   y: string | number | boolean;
//   b: string | number | boolean;
// }

// 期望的类型:
// type X = {
//   x: string;
//   y: number;
//   b: boolean;
// }

问题原因

Record<keyof T, T[keyof T]>的类型定义存在问题:

  • T[keyof T]会提取T所有属性值类型的联合(这里是string | number | boolean)
  • Record类型会把keyof T中的每个键都映射到这个联合类型,导致所有属性的类型都被统一为混合类型

解决方案

方案1:将返回类型改为T

直接让函数返回输入实例的类型T,并调整类型断言:

class XClass {
  x = "x";
  y = 11;
  b = true;
}
let xObj = new XClass();
function getSchema<T extends XClass>(instance: T): T {
  const returnObj = {} as T;
  for (const key in instance) {
    returnObj[key] = instance[key];
  }
  return returnObj;
}
let schema = getSchema(xObj);
type X = typeof schema;
// 推断结果符合预期:x:string, y:number, b:boolean

方案2:使用精确映射类型替代Record

显式使用映射类型{ [K in keyof T]: T[K] },为每个键保留对应的原始类型:

function getSchema<T extends XClass>(instance: T): { [K in keyof T]: T[K] } {
  const returnObj = {} as { [K in keyof T]: T[K] };
  for (const key in instance) {
    returnObj[key] = instance[key];
  }
  return returnObj;
}

方案3:用Object.assign简化实现

Object.assign会自动推断正确的返回类型,无需手动循环和断言:

function getSchema<T extends XClass>(instance: T): T {
  return Object.assign({}, instance);
}

说明

映射类型{ [K in keyof T]: T[K] }和T本质等价,都会完整复刻原类型的结构与属性类型。Record类型更适合所有键对应相同类型的场景,不适合需要保留属性独立类型的需求。

内容的提问来源于stack exchange,提问作者Nihfur lourag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 23:55:21