Skip to content
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

TS: defineComponent doesn't return a Component #993

Closed
jods4 opened this issue Apr 19, 2020 · 3 comments · Fixed by #1032
Closed

TS: defineComponent doesn't return a Component #993

jods4 opened this issue Apr 19, 2020 · 3 comments · Fixed by #1032
Labels

Comments

@jods4
Copy link
Contributor

jods4 commented Apr 19, 2020

Version

3.0.0-beta.2

Reproduction link

https://codesandbox.io/s/amazing-meitner-tgk24?file=/src/main.ts

Steps to reproduce

See main.ts in repro.

I'm having typing issues with defineComponent once more, it seems to me the root cause is that defineComponent TS definition pretends to return a ctor when it does not.

This time the offender is Component: a union type that includes both stateful and functional components but not ctor, which would be ok if defineComponent wasn't lying about its return type.

Out of curiosity, I looked at how createApp manages to do it: its first argument is a PublicApiComponent, which turns out to be... the union of Component and Ctor!
This is just confusing, not to mention PublicApiComponent is not exported, so there's no type in Vue API that can be used to describe a "component" type that would work in all cases.

What is expected?

Code should compile? Or a good alternative be provided?

What is actually happening?

TS error as Ctor is not a Component.

@pikax
Copy link
Member

pikax commented Apr 23, 2020

From what I've learned, defineComponent return ctor is actually an hack to make h do some validations.

I've done also an hack to make defineComponent return an Component valid. After sleeping over my solution, still not happy with it, personally I think having PublicAPIComponent as the public type component would be better and use Component to more internal type, this would require some name change.

@jods4
Copy link
Contributor Author

jods4 commented Apr 23, 2020

@pikax that's fine, I figured there had to be a reason why defineComponent isn't returning the real type.

From a public API perspective, can I suggest that you do a bit of renaming type? Can Component be the public, usable type (i.e. the current PublicAPIComponent); and the current Component becomes some CompositionComponent or whatever and we make sure that it's never exported in public api surfaces?

@pikax
Copy link
Member

pikax commented Apr 24, 2020

Even with the rename it makes really hard to enforce the correct types validation, because when you have the interface Component that is generic, the enforcing of the props becomes really hard.

The tests I was getting trouble with were the h-dts

if we are too loose, this will not pass

describe('h inference w/ Fragment', () => {
  // only accepts array children
  h(Fragment, ['hello'])
  h(Fragment, { key: 123 }, ['hello'])
  expectError(h(Fragment, 'foo'))
  expectError(h(Fragment, { key: 123 }, 'bar'))
})

making the it too strict will make this fail

// #922
describe('h support for generic component type', () => {
  function foo(bar: Component) {
    h(bar)
    h(bar, 'hello')
    h(bar, { id: 'ok' }, 'hello')
  }
  foo({})
})

Because we want prop typescript validation, we can't be too loose on the validation.

pikax added a commit to pikax/vue-next that referenced this issue Apr 29, 2020
@github-actions github-actions bot locked and limited conversation to collaborators Nov 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants