This is a spin-off Question of
Any idea to fix this error? Thanks!
CodePudding user response:
This is because when you call Object.defineProperty
typescript isn't able to infer that the type of the field has changed. Actually you shouldn't use defineProperty
here, there is no point in it, just use normal assignment. So let's rewrite this code a little simplified:
// Not quite clear to me why you wrapped this in an immediately
// invoked function, but for simplicity I'll unwrap it
const obj = _P(undefined)
const P =
<T>(x: T) => {
// Don't use `defineProperty` because there is no point in it
// Also name the argument for `R` function differently
// in order to not get confused what `x` actually is
obj.foo = <U>(R: (arg: T) => U) => R(x)
};
Here defineProperty
actually hid the real error:
Type '<U>(R: (arg: T) => U) => U' is not assignable to
type '<U>(R: (arg: undefined) => U) => U'
The defineProperty
just bypassed type checking so you couldn't see what caused the error.
Speaking about fixing it, I cannot really suggest anything, because it's unclear to me what you are trying to do. When P
was creating a new object after every call, it was clear: multiple callers could get their own instances of this object and foo
function, every of this instances could accept its own type of arguments. Here however, it is not the case: you have only one {foo: ...}
object for your entire application, so it is not possible for it to accept different kinds of arguments. Remember, it's not obligatory that foo
function be called right after the P
call, for example imagine this scenario.
const b = P('abc')
const c = P(99)
How is it supposed to work? Remember, there is only one { foo: ... }
object in the entire application. After instantiating b
in the snippet above, this object becomes
// (1)
{
foo: <U>(R: (arg: string) => U) => R('abc'),
}
But after instantiating c
, this very same object changes: it suddenly becomes
// (2)
{
foo: <U>(R: (arg: number) => U) => R(9),
}
What is now supposed to happen when you call b.foo(a => a.repeat(2))
for example? According to what you probably expect, the function you pass to foo
should be called with 'abc'
and it should return 'abcabc'
. However the foo
function is now like in snippet (2)
, so what will actually happen is that the function you passed to foo
will be called with 99
which doesn't have a method called repeat
so this will throw a runtime error. So whatever you are trying to do, this will not work.
Also it's not quite clear what is the motivation to "avoid the new object creation on every call". In javascript the time it takes to create an object and the amount of memory it occupies is usually negligible. You most definitely should not care about it unless you are writing something ridiculously performance intensive or unless you have hundreds of millions of such objects. Another thing to consider is that mutating objects is not always a good thing, especially in this case. It is pretty hard to manage and will cause lots of headache. So please think twice before implementing whatever you are trying to implement