5

I have a renderless component in JavaScript that I am trying to convert to TypeScript. I'm running into errors declaring the render function in a Vue.extend-ed component:

(method) ComponentOptions<Vue, unknown, unknown, unknown, never[], Record<never, any>>.render?(createElement: CreateElement, hack: RenderContext<Record<never, any>>): VNode
  No overload matches this call.
  The last overload gave the following error.
  Argument of type '{ render(): void; }' is not assignable to parameter of type 'ComponentOptions<Vue, DefaultData<Vue>, DefaultMethods<Vue>, DefaultComputed, PropsDefinition<Record<string, any>>, Record<string, any>>'.
    Types of property 'render' are incompatible.
      Type '() => void' is not assignable to type '(createElement: CreateElement, hack: RenderContext<Record<string, any>>) => VNode'.
        Type 'void' is not assignable to type 'VNode'.ts(2769)
        vue.d.ts(90, 3): The last overload is declared here.

This is an example of what I am trying to do in TypeScript:

import Vue from 'vue'

export default Vue.extend({
  render() { // error happens when I add this. I tried typing the render with :VNode
             // and returning this.$scopedSlots.default({}), but error still occurs
  }
})

How do I fix this?

2
  • What do you mean by - send props back to a parent component? Can you share original code snippet? Commented Sep 19, 2019 at 2:52
  • learn-vuejs.github.io/vue-patterns/patterns/… this is what a renderless component is and this is what I want to achieve only with typescript Commented Sep 19, 2019 at 8:41

1 Answer 1

8

render() has this signature:

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

Notes for render() declaration:

  • hack does not need to be declared in your code
  • argument declarations are unnecessary in a renderless function
  • return type is VNode (i.e., a single root node), but Vue actually accepts VNode[] as a return (which is what this.$scopedSlots.default() returns)

Solution 1: Specify the return type as VNode, and return a single node that wraps this.$scopedSlots.default():

import Vue, { VNode, CreateElement } from 'vue'

export default Vue.extend({
  render(h: CreateElement): VNode {
    return h('div', this.$scopedSlots.default!({}))
  }
})

Solution 2: Use any type assertion on this.$scopedSlots.default() to workaround the type error:

import Vue from 'vue'

export default Vue.extend({
  render() {
    // The container node is expected to provide a single root,
    // so it's okay to return `VNode[]` as any.
    return this.$scopedSlots.default!({}) as any
  }
})
Sign up to request clarification or add additional context in comments.

3 Comments

solution 2 worked for me because the component is renderless. Thank you @tony19. This isn't available to know in the docs so thank you for sharing your knowledge.
I've got error using second solution, but using normal slot works fine: render() { return this.$slots.default! as any }
Yeah, above solution worked as long as I did not use mixin (defined unfortunetly as any). Adding mixin resulted in ts errors on every component property. Now I'm using `render(h) { return h('template') } and seems to work perfectly fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.