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

如何为支持任意属性的JavaScript Proxy编写精确TypeScript类型?

为支持任意属性访问的JavaScript Proxy编写精确TypeScript类型

问题描述

我需要为支持任意属性访问的JavaScript Proxy编写TypeScript类型。举个简化示例:一个能将每个属性映射为自身属性名的对象:

const proxy = new Proxy({}, {
  get(target, property) {
    return property;
  }
});
proxy.foo // 实际求值为"foo"
// 但TypeScript报错:Property 'foo' does not exist on type '{}'.ts(2339)

我不指望TypeScript自动推断proxy.foo存在,但希望通过类型定义让它知晓任意属性都存在,且属性值的类型与属性名完全一致。

用普通的映射类型虽然能消除属性不存在的报错,但会把值类型推断为string而非更精确的"foo":

const proxy = new Proxy<{ [T in string]: T }>({}, {
  get(target, prop) {
    return prop;
  }
});
proxy.foo // 推断类型为string,而非预期的"foo"

我也试过{ readonly [T in string]: T },有意思的是,({} as { [T in "foo" | "bar"]: T }).foo会被正确推断为"foo",但我没办法枚举所有可能的键。

有没有办法让TypeScript在映射类型中把精确键名作为值类型,或者通过其他方式为带动态属性的Proxy编写精确类型?

解决方案

方案1:泛型索引类型结合类型断言

定义包含泛型索引签名的类型,通过类型断言为Proxy实例绑定该类型,TypeScript会在访问具体属性时自动推导键名的字面量类型:

type SelfReferencingProxy = {
  [K: string]: K;
};

const proxy = new Proxy({}, {
  get(target, prop) {
    return prop;
  }
}) as SelfReferencingProxy;

const foo = proxy.foo; // 类型推断为 "foo"
const customKey = proxy['user-name_123']; // 类型推断为 "user-name_123"

方案2:封装为泛型创建函数

把Proxy的创建逻辑封装成函数,返回值直接绑定目标类型,代码结构更清晰:

type SelfProxy = { [K: string]: K };

function createSelfProxy(): SelfProxy {
  return new Proxy({}, {
    get(target, prop) {
      return prop;
    }
  });
}

const proxy = createSelfProxy();
const bar = proxy.bar; // 类型推断为 "bar"

原理说明

TypeScript默认处理索引签名时,会将值类型推断为键类型的联合(比如string),但当你将Proxy断言为{ [K: string]: K }这类泛型索引类型后,TypeScript会利用上下文类型推断能力,在访问具体属性时把当前键名的字面量类型代入到索引签名的K中,从而得到与键名完全一致的值类型。

对于已知枚举键的场景,TypeScript能直接匹配键与值的类型;而对于任意键的动态场景,通过上述方式让TypeScript在属性访问时动态推导,就能实现精确的类型约束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 18:52:35