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

如何在TypeScript中以类型安全的方式设置对象引用?

类型安全的双向对象关联函数实现

需求说明

需要实现一个wire函数,完成两个对象的双向关联:将object1.field1赋值为object2,同时将object2.field2赋值为object1。要求:

  • 类型安全:只能选择类型匹配的字段(比如Animal的owner1/owner2字段类型为Person,才能和Person对象关联,numberOfLegs类型不匹配则无法选择)
  • IDE自动补全支持:输入参数时能自动提示符合条件的字段名

错误实现分析

你之前的泛型约束逻辑存在问题,S1 extends F1 & (T1[F1] extends T2 ? F1 : never)这种写法无法正确筛选出目标字段,因为泛型参数的层级关系导致TypeScript无法正确推断出符合条件的键集合。

正确实现方案

首先定义一个工具类型,用来提取对象中值类型匹配指定类型的键:

// 工具类型:提取T中值类型兼容U的所有键
type KeysOfType<T, U> = { [K in keyof T]: T[K] extends U ? K : never }[keyof T];

然后基于这个工具类型实现wire函数:

type KeysOfType<T, U> = { [K in keyof T]: T[K] extends U ? K : never }[keyof T];

function wire<T1, T2>(
  o1: T1,
  o2: T2,
  f1: KeysOfType<T1, T2>,
  f2: KeysOfType<T2, T1>
) {
  // 类型断言确保赋值安全,因为泛型约束已保证类型兼容
  o1[f1] = o2 as T1[typeof f1];
  o2[f2] = o1 as T2[typeof f2];
}

测试示例

type Person = {
  animal1: Animal;
  animal2: Animal;
  name: string;
};

type Animal = {
  owner1: Person;
  owner2: Person;
  numberOfLegs: number;
};

// 初始化对象
let animal: Animal = {
  owner1: {} as Person,
  owner2: {} as Person,
  numberOfLegs: 4
};
let person: Person = {
  animal1: {} as Animal,
  animal2: {} as Animal,
  name: "Alice"
};

// ✅ 合法调用:IDE会自动补全f1为owner1/owner2,f2为animal1/animal2
wire(animal, person, "owner1", "animal1");

// ❌ 非法调用:numberOfLegs类型为number,与Person不匹配,TypeScript会报错
// wire(animal, person, "numberOfLegs", "animal1");

// ❌ 非法调用:name类型为string,与Animal不匹配,TypeScript会报错
// wire(animal, person, "owner1", "name");

实现原理

  • KeysOfType<T, U>通过映射类型遍历对象的所有键,仅保留值类型兼容U的键,精准筛选出可用于关联的字段。
  • 函数的泛型参数T1和T2分别对应两个关联对象的类型,参数f1和f2被约束为各自对象中符合类型要求的键,从根源保证类型安全。
  • 赋值时的类型断言是安全的,因为泛型约束已经确保了o2可以赋值给o1[f1]、o1可以赋值给o2[f2]。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 18:45:49