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

TypeScript错误2345修复咨询:复用对象重定义属性方法时的类型不兼容问题

Fixing TypeScript Error 2345 When Reusing Object with Object.defineProperty

Let's break down why you're seeing this error and how to fix it.

Why the Error Happens

Your initial obj is created with _P(undefined), so TypeScript infers its foo method expects a function that takes an undefined parameter. Even though you overwrite foo's value at runtime using Object.defineProperty, TypeScript's static type system doesn't track this dynamic change. It still sees the original type of foo (accepting (x: undefined) => U), hence the mismatch when you pass (a: number) => number.

The fact that b gets the correct number type is due to TypeScript's contextual inference—it can guess the intended type from how you're using f and P(99), but this doesn't override the static type check on the foo method itself.

Fix 1: Type Assertion for the Returned Object

The simplest fix is to assert that the modified object matches the correct generic type returned by _P<T>. We'll create a type alias for that return type first:

const _P = <T,>(x: T) => ({ "foo": <U,>(R: (x: T) => U) => R(x) });
// Define the return type of _P<T>
type PInstance<T> = ReturnType<typeof _P<T>>;

const P = (obj => <T,>(x: T) => 
  // Assert the modified object is of type PInstance<T>
  Object.defineProperty(obj, "foo", {
    configurable: true,
    value: <U,>(R: (x: T) => U) => R(x)
  }) as PInstance<T>
)(_P(undefined));

const f = (a: number) => a + 1;
const b = P(99)['foo'](f); // No error now! Type of b is number
console.log(b); // 100

By asserting the result of Object.defineProperty as PInstance<T>, we tell TypeScript to ignore the original undefined-based type and use the generic type corresponding to the current x parameter.

Fix 2: Explicitly Type the P Function

Another approach is to define the exact type you want P to have, then assert the implementation matches that type. This makes the intended behavior clearer to readers:

const _P = <T,>(x: T) => ({ "foo": <U,>(R: (x: T) => U) => R(x) });
// Define the desired type for P
type PFunction = <T>(x: T) => {
  foo: <U>(R: (x: T) => U) => U;
};

const P = ((obj) => <T,>(x: T) => 
  Object.defineProperty(obj, "foo", {
    configurable: true,
    value: <U,>(R: (x: T) => U) => R(x)
  })
)(_P(undefined)) as PFunction;

const f = (a: number) => a + 1;
const b = P(99)['foo'](f); // No error, type inference works correctly
console.log(b); // 100

Why This Works

Both fixes essentially override TypeScript's static view of the object's type to align with your runtime behavior. Since you're intentionally reusing the same object and updating its method dynamically, you need to bridge the gap between TypeScript's static analysis and your dynamic code.

Alternative: Avoid Dynamic Property Overwrites (If Possible)

If you're open to a slightly different implementation that avoids Object.defineProperty entirely while still being efficient, you could use a class with a mutable state. This keeps TypeScript's type system happy without needing assertions:

class PWrapper<T> {
  private currentValue: T;

  constructor(initialValue: T) {
    this.currentValue = initialValue;
  }

  updateValue<T>(newValue: T): PWrapper<T> {
    (this as unknown as PWrapper<T>).currentValue = newValue;
    return this as unknown as PWrapper<T>;
  }

  foo<U>(R: (x: T) => U): U {
    return R(this.currentValue);
  }
}

const P = <T>(x: T) => new PWrapper(undefined as unknown as T).updateValue(x);

const f = (a: number) => a + 1;
const b = P(99).foo(f); // No error, type is number
console.log(b); // 100

This reuses the same instance (like your original approach) but uses TypeScript's class system to manage type changes safely.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 21:59:06