Skip to content

Function adding property type error #55303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
zclsx opened this issue Aug 8, 2023 · 18 comments
Closed

Function adding property type error #55303

zclsx opened this issue Aug 8, 2023 · 18 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@zclsx
Copy link

zclsx commented Aug 8, 2023

🔎 Search Terms

Function addition attribute

🕗 Version & Regression Information

No solution is provided in typescript

⏯ Playground Link

No response

💻 Code

interface ReactiveEffectRunner<T = any> {
  (): T;
  effect: ReactiveEffect;
}
  const runner = _effect.run.bind(_effect) as ReactiveEffectRunner;

  runner.effect = _effect;

🙁 Actual behavior

const runner:ReactiveEffectRunner = _effect.run.bind(_effect);

When we use type annotations this way, we get an error: type "() => Missing attribute "effect" in any" but type "ReactiveEffectRunner< any>" This property is required in.

🙂 Expected behavior

How do we assign properties to a function if we don't use as to make assertions?

I needed typescript to provide a solution for us to solve the problem of incorrect function assignment types, instead of using crude assertions to solve it. Because typescript can put forward solutions to solve problems, it will make the code more elegant. Looking forward to your reply, thank you! 🙏

### Tasks
@jcalz
Copy link
Contributor

jcalz commented Aug 8, 2023

What is _effect? Where's the playground link? What, specifically, makes you think that this is a bug in the language instead of a question about how to do something (which would belong more on Stack Overflow or the TS Discord)?

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

What is _effect? Where's the playground link? What, specifically, makes you think that this is a bug in the language instead of a question about how to do something (which would belong more on Stack Overflow or the TS Discord)?
This is what the vue3 code does, js is acceptable for assigning attributes to functions, but ts I didn't find out how to define the type for the runner so that it can be used as a function and be able to be assigned attributes, the simple brute force as is itself a forced conversion of the type, I don't see this as a bug, but rather an unimplemented feature

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

What is _effect? Where's the playground link? What, specifically, makes you think that this is a bug in the language instead of a question about how to do something (which would belong more on Stack Overflow or the TS Discord)?

https://github.com/vuejs/core/blob/main/packages/reactivity/src/effect.ts

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

What is _effect? Where's the playground link? What, specifically, makes you think that this is a bug in the language instead of a question about how to do something (which would belong more on Stack Overflow or the TS Discord)?
Beginning of row 180

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

What is _effect? Where's the playground link? What, specifically, makes you think that this is a bug in the language instead of a question about how to do something (which would belong more on Stack Overflow or the TS Discord)?
We can only re-assert run as a 'ReavtiveEffectRunner' type, effect, which the runner is able to call directly, and runner.effect, which is also able to get the effect function

@jcalz
Copy link
Contributor

jcalz commented Aug 8, 2023

  • There's a different template for feature requests, this was filed as a bug report.
  • All relevant code should ideally be contained here in the issue and not only available at a link
  • You might be using some other UI to interact with this issue but I suggest you don't keep adding new comments each time you have something to say if nobody has posted an intervening comment. You can edit existing comments as well.
  • If you blockquote something you should make sure that the response isn't included in the quote or it's hard for others to see where the quote ends and your response begins.

@whzx5byb
Copy link

whzx5byb commented Aug 8, 2023

How do we assign properties to a function if we don't use as to make assertions?

I'd suggest using Object.assign instead of assign properties directly. In this way the code you posted in #55303 (comment) could be written as:

-  const runner = _effect.run.bind(_effect) as ReactiveEffectRunner
-  runner.effect = _effect
-  return runner
+  return Object.assign(_effect.run.bind(_effect), { effect: _effect })

@zclsx
Copy link
Author

zclsx commented Aug 8, 2023

How do we assign properties to a function if we don't use as to make assertions?

I'd suggest using Object.assign instead of assign properties directly. In this way the code you posted in #55303 (comment) could be written as:

-  const runner = _effect.run.bind(_effect) as ReactiveEffectRunner
-  runner.effect = _effect
-  return runner
+  return Object.assign(_effect.run.bind(_effect), { effect: _effect })

First of all, thank you for your reply above, so that I can solve the problem in this way.

Although this solves the problem at hand, after assigning a value to the runner and before assigning an effect, so that you can't use Object. assign for the merge operation, the function return run function will result in the unit test not being passed.I don't seem to find a way to solve this problem directly in typescript, but instead do other parts of the code to solve the types in the ts part.

But under certain conditions I have to assign the two separately, so this way the merge operation doesn't work, ts doesn't provide a direct solution for this, which confuses me, I appreciate your response, thanks a lot!

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

How do we assign properties to a function if we don't use as to make assertions?

I'd suggest using Object.assign instead of assign properties directly. In this way the code you posted in #55303 (comment) could be written as:

-  const runner = _effect.run.bind(_effect) as ReactiveEffectRunner
-  runner.effect = _effect
-  return runner
+  return Object.assign(_effect.run.bind(_effect), { effect: _effect })

I also endorse zclsx's statement

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Aug 8, 2023
@fatcerberus
Copy link

But under certain conditions I have to assign the two separately

In that case the error message is correct: the type says that the property always exists, but there’s an observable period of time where it’s missing. That’s a real type violation, and it makes sense that you have to write a type assertion to acknowledge it.

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

But under certain conditions I have to assign the two separately

In that case the error message is correct: the type says that the property always exists, but there’s an observable period of time where it’s missing. That’s a real type violation, and it makes sense that you have to write a type assertion to acknowledge it.

So why is it that objects are guaranteed to be of the correct type when they are subsequently supplemented with relevant attributes, but functions are not guaranteed to be of the correct type when they are subsequently supplemented with attributes?

I'm curious. thanks

@fatcerberus
Copy link

I don’t know where you got that idea. Leaving properties off of an object to be assigned later is an error too.

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

I don’t know where you got that idea. Leaving properties off of an object to be assigned later is an error too.

I'm sorry, it's just me, but I need to do some logical processing between two assignment operations, how do I get there in this case without using assertions?

type Effect = () => void
interface Runner {
    (): void
    effect: Effect
}

function run() {
    console.log('run');
}

function effect() {
    console.log('effect');
}

// Using function returns can cause unit tests to fail
// const runner: Runner = () => run  
const runner: Runner = run
//Logic handling between run and effect
runner.effect = effect

@whzx5byb
Copy link

whzx5byb commented Aug 8, 2023

@Andy-gs

You can always use Object.assign to perform the assignment of expando properties to a function. But unfortunately, since #40562 or #42253 has not been implemented, Object.assign cannot be used as an assertion function to reflect the type change of the target.

Instead, you could write a custom function as a workaround.

function assign<T extends {}, U>(target: T, source: U): asserts target is T & U {
    Object.assign(target, source);
}

const runner = run
//Logic handling between run and effect
assign(runner, { effect });

runner;
// ^? const runner: (() => void) & { effect: () => void; }

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

@Andy-gs

You can always use Object.assign to perform the assignment of expando properties to a function. But unfortunately, since #40562 or #42253 has not been implemented, Object.assign cannot be used as an assertion function to reflect the type change of the target.

Instead, you could write a custom function as a workaround.

function assign<T extends {}, U>(target: T, source: U): asserts target is T & U {
    Object.assign(target, source);
}

const runner = run
//Logic handling between run and effect
assign(runner, { effect });

runner;
// ^? const runner: (() => void) & { effect: () => void; }

SuperCool
SuperCool
SuperCool
Niubi(Chinese)
牛逼

@zclsx
Copy link
Author

zclsx commented Aug 8, 2023

@Andy-gs

You can always use Object.assign to perform the assignment of expando properties to a function. But unfortunately, since #40562 or #42253 has not been implemented, Object.assign cannot be used as an assertion function to reflect the type change of the target.

Instead, you could write a custom function as a workaround.

function assign<T extends {}, U>(target: T, source: U): asserts target is T & U {
    Object.assign(target, source);
}

const runner = run
//Logic handling between run and effect
assign(runner, { effect });

runner;
// ^? const runner: (() => void) & { effect: () => void; }

Thank you for your guidance! This is crazy! pretty cool

@Andy-gs
Copy link

Andy-gs commented Aug 8, 2023

@Andy-gs

You can always use Object.assign to perform the assignment of expando properties to a function. But unfortunately, since #40562 or #42253 has not been implemented, Object.assign cannot be used as an assertion function to reflect the type change of the target.

Instead, you could write a custom function as a workaround.

function assign<T extends {}, U>(target: T, source: U): asserts target is T & U {
    Object.assign(target, source);
}

const runner = run
//Logic handling between run and effect
assign(runner, { effect });

runner;
// ^? const runner: (() => void) & { effect: () => void; }

ts No plans to implement this feature?

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Question" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Aug 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

7 participants