TypeScript错误2345修复咨询:复用对象重定义属性方法时的类型不兼容问题
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

