> | string[]
+ },
+ options?: MountingOptions & Record
+): Promise
+
+// Class component - no props
+export function renderToString(
+ originalComponent: {
+ new (...args: any[]): V
+ registerHooks(keys: string[]): void
+ },
+ options?: MountingOptions & Record
+): Promise
+
+// Class component - props
+export function renderToString(
+ originalComponent: {
+ new (...args: any[]): V
+ props(Props: P): any
+ registerHooks(keys: string[]): void
+ },
+ options?: MountingOptions & Record
+): Promise
+
+// Functional component with emits
+export function renderToString(
+ originalComponent: FunctionalComponent,
+ options?: MountingOptions & Record
+): Promise
+
+// Component declared with defineComponent
+export function renderToString<
+ PropsOrPropOptions = {},
+ RawBindings = {},
+ D = {},
+ C extends ComputedOptions = ComputedOptions,
+ M extends MethodOptions = MethodOptions,
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
+ E extends EmitsOptions = Record,
+ EE extends string = string,
+ PP = PublicProps,
+ Props = Readonly>,
+ Defaults extends {} = ExtractDefaultPropTypes
+>(
+ component: DefineComponent<
+ PropsOrPropOptions,
+ RawBindings,
+ D,
+ C,
+ M,
+ Mixin,
+ Extends,
+ E,
+ EE,
+ PP,
+ Props,
+ Defaults
+ >,
+ options?: MountingOptions<
+ Partial & Omit,
+ D
+ > &
+ Record
+): Promise
+
+// component declared by vue-tsc ScriptSetup
+export function renderToString<
+ T extends DefineComponent
+>(component: T, options?: ComponentMountingOptions): Promise
+
+// Component declared with no props
+export function renderToString<
+ Props = {},
+ RawBindings = {},
+ D extends {} = {},
+ C extends ComputedOptions = {},
+ M extends Record = {},
+ E extends EmitsOptions = Record,
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
+ EE extends string = string
+>(
+ componentOptions: ComponentOptionsWithoutProps<
+ Props,
+ RawBindings,
+ D,
+ C,
+ M,
+ E,
+ Mixin,
+ Extends,
+ EE
+ >,
+ options?: MountingOptions
+): Promise
+
+// Component declared with { props: [] }
+export function renderToString<
+ PropNames extends string,
+ RawBindings,
+ D extends {},
+ C extends ComputedOptions = {},
+ M extends Record = {},
+ E extends EmitsOptions = Record,
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
+ EE extends string = string,
+ Props extends Readonly<{ [key in PropNames]?: any }> = Readonly<{
+ [key in PropNames]?: any
+ }>
+>(
+ componentOptions: ComponentOptionsWithArrayProps<
+ PropNames,
+ RawBindings,
+ D,
+ C,
+ M,
+ E,
+ Mixin,
+ Extends,
+ EE,
+ Props
+ >,
+ options?: MountingOptions
+): Promise
+
+// Component declared with { props: { ... } }
+export function renderToString<
+ // the Readonly constraint allows TS to treat the type of { required: true }
+ // as constant instead of boolean.
+ PropsOptions extends Readonly,
+ RawBindings,
+ D extends {},
+ C extends ComputedOptions = {},
+ M extends Record = {},
+ E extends EmitsOptions = Record,
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
+ EE extends string = string
+>(
+ componentOptions: ComponentOptionsWithObjectProps<
+ PropsOptions,
+ RawBindings,
+ D,
+ C,
+ M,
+ E,
+ Mixin,
+ Extends,
+ EE
+ >,
+ options?: MountingOptions & PublicProps, D>
+): Promise
+
+export function renderToString(component: any, options?: any): Promise {
+ const { app } = createInstance(component, options)
+ return baseRenderToString(app)
+}
diff --git a/test-dts/renderToString.d-test.ts b/test-dts/renderToString.d-test.ts
new file mode 100644
index 000000000..02c8a3361
--- /dev/null
+++ b/test-dts/renderToString.d-test.ts
@@ -0,0 +1,107 @@
+import { expectError, expectType } from './index'
+import { defineComponent } from 'vue'
+import { Options, Vue } from 'vue-class-component'
+import { renderToString } from '../src'
+
+const AppWithDefine = defineComponent({
+ props: {
+ a: {
+ type: String,
+ required: true
+ },
+ b: Number
+ },
+ template: ''
+})
+
+// accept props
+let html = renderToString(AppWithDefine, {
+ props: { a: 'Hello', b: 2 }
+})
+// html is properly typed
+expectType>(html)
+
+// allow extra props, like using `h()`
+renderToString(AppWithDefine, {
+ props: { a: 'Hello', c: 2 }
+})
+
+expectError(
+ // @ts-expect-error wrong prop type should not compile
+ renderToString(AppWithDefine, {
+ props: { a: 2 }
+ })
+)
+
+const AppWithProps = {
+ props: {
+ a: {
+ type: String,
+ required: true
+ }
+ },
+ template: ''
+}
+
+// accept props
+expectType>(
+ renderToString(AppWithProps, {
+ props: { a: 'Hello' }
+ })
+)
+
+// allow extra props, like using `h()`
+renderToString(AppWithProps, {
+ props: { a: 'Hello', b: 2 }
+})
+
+expectError(
+ renderToString(AppWithProps, {
+ // @ts-expect-error wrong prop type should not compile
+ props: { a: 2 }
+ })
+)
+
+const AppWithArrayProps = {
+ props: ['a'],
+ template: ''
+}
+
+// accept props
+html = renderToString(AppWithArrayProps, {
+ props: { a: 'Hello' }
+})
+expectType>(html)
+
+// can receive extra props
+// as they are declared as `string[]`
+renderToString(AppWithArrayProps, {
+ props: { a: 'Hello', b: 2 }
+})
+
+const AppWithoutProps = {
+ template: ''
+}
+
+// allow extra props, like using `h()`
+html = renderToString(AppWithoutProps, {
+ props: { b: 'Hello' }
+})
+
+// class component
+@Options({
+ props: {
+ msg: String
+ }
+})
+class ClassComponent extends Vue {
+ dataText = ''
+ get computedMsg(): string {
+ return `Message: ${(this.$props as any).msg}`
+ }
+
+ changeMessage(text: string): void {
+ this.dataText = 'Updated'
+ }
+}
+expectType>(renderToString(ClassComponent))
diff --git a/tests/renderToString.spec.ts b/tests/renderToString.spec.ts
new file mode 100644
index 000000000..eb1669fae
--- /dev/null
+++ b/tests/renderToString.spec.ts
@@ -0,0 +1,59 @@
+import { describe, it, expect } from 'vitest'
+import { defineComponent, onMounted, onServerPrefetch, ref } from 'vue'
+import { renderToString } from '../src'
+
+describe('renderToString', () => {
+ it('returns a promise', async () => {
+ const Component = defineComponent({
+ template: '{{ text }}
',
+ setup() {
+ return { text: 'Text content' }
+ }
+ })
+
+ const wrapper = await renderToString(Component)
+
+ expect(wrapper).toMatchInlineSnapshot(`"Text content
"`)
+ })
+
+ it('returns correct html on multi root nodes', async () => {
+ const Component = defineComponent({
+ template: 'foo
bar
'
+ })
+
+ const wrapper = await renderToString(Component)
+
+ expect(wrapper).toMatchInlineSnapshot(
+ `"foo
bar
"`
+ )
+ })
+
+ it('returns correct html with pre-fetched data on server', async () => {
+ function fakeFetch(text: string) {
+ return Promise.resolve(text)
+ }
+
+ const Component = defineComponent({
+ template: '{{ text }}
',
+ setup() {
+ const text = ref(null)
+
+ onServerPrefetch(async () => {
+ text.value = await fakeFetch('onServerPrefetch')
+ })
+
+ onMounted(async () => {
+ if (!text.value) {
+ text.value = await fakeFetch('onMounted')
+ }
+ })
+
+ return { text }
+ }
+ })
+
+ const contents = await renderToString(Component)
+
+ expect(contents).toBe('onServerPrefetch
')
+ })
+})