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

TypeScript ComponentOptions render return type is restricted to VNode, but Vue allows VNode[] too #10905

Closed
bbugh opened this issue Dec 7, 2019 · 2 comments

Comments

@bbugh
Copy link

bbugh commented Dec 7, 2019

Version

2.6.10

Reproduction link

https://codesandbox.io/s/vue-typescript-example-ptkbu?module=%2Fsrc%2Fcomponents%2FExample.vue

Steps to reproduce

This is a simple reproduction and the codesandbox might make more sense than this explanation.

Returning scoped slot like this works fine, when not using TypeScript:

// This works fine without TypeScript
render (h) {
  return this.$scopedSlots.default({
    action: this.action
  })
}

In TypeScript, this equivalent code fails. defaultSlot is a VNode[], but the render function only allows a VNode. Here's the example with checking all of the possible undefineds:

// The type-safe equivalent in TypeScript is
render (h) {
  if (this.$scopedSlots && this.$scopedSlots.default) {
    const defaultSlot = this.$scopedSlots.default({
      action: this.action
    })

    if (defaultSlot) {
      return defaultSlot // This is VNode[] but render demands a VNode
    }
  }

  return h('div') // for this example proof of type safety
}

The error statement:

No overload matches this call.
  The last overload gave the following error.
    Argument of type '{ props: { project: { type: ObjectConstructor; required: true; }; }; methods: { deleteProject(): void; }; render(h: CreateElement): VNode[] | VNode; }' is not assignable to parameter of type 'ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, PropsDefinition<Record<string, any>>, Record<...>>'.
      The types returned by 'render(...)' are incompatible between these types.
        Type 'VNode[] | VNode' is not assignable to type 'VNode'.
          Type 'VNode[]' is missing the following properties from type 'VNode': isRootInsert, isComment

What is expected?

The render return type allows all valid return types. In this case, it's at least VNode[] | VNode.

-  render?(createElement: CreateElement, hack: RenderContext<Props>): VNode;
+  render?(createElement: CreateElement, hack: RenderContext<Props>): VNode | VNode[];

There might be others valid types?

What is actually happening?

return defaultSlot is expecting a VNode[] but the render typing only accepts a VNode.

The only way to work around this now is to cast to any when returning a value, which is a hack.


Source line for render function:

render?(createElement: CreateElement, hack: RenderContext<Props>): VNode;

@posva
Copy link
Member

posva commented Dec 8, 2019

The error makes sense, you cannot return an array of vnodes, only an array of one vnode (#8056). This was to avoid breaking changes. Regarding types, however, it makes sense to make it strict.

@posva posva closed this as completed Dec 8, 2019
@bbugh
Copy link
Author

bbugh commented Dec 8, 2019

That's very odd behavior. Thank you for the history, I can see how it ended up that way. Seems like the correct code is to return defaultSlot[0].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants