diff --git a/package.json b/package.json
index 3c2760a..a3b7b08 100644
--- a/package.json
+++ b/package.json
@@ -68,9 +68,11 @@
     "lodash.merge": "^4.6.2",
     "msw": "^1.3.2",
     "tsd": "^0.29.0",
+    "type-fest": "~2.19",
     "typescript": "^5.2.2",
     "vee-validate": "^4.11.8",
     "vue": "^3.3.5",
+    "vue-component-type-helpers": "^2.0.19",
     "vue-eslint-parser": "^9.3.2",
     "vue-i18n": "^9.5.0",
     "vue-router": "^4.2.5",
diff --git a/src/__tests__/render.js b/src/__tests__/render.js
index ea55817..235210e 100644
--- a/src/__tests__/render.js
+++ b/src/__tests__/render.js
@@ -1,6 +1,6 @@
-import {render, cleanup} from '..'
 import {h, defineComponent} from 'vue'
 import '@testing-library/jest-dom'
+import {render, cleanup} from '..'
 
 test('baseElement defaults to document.body', () => {
   const {baseElement} = render({template: '<div />'})
diff --git a/types/index.d.ts b/types/index.d.ts
index c6c157d..d4edc3b 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -1,10 +1,13 @@
 // Minimum TypeScript Version: 4.0
 /* eslint-disable @typescript-eslint/no-explicit-any */
 
+import {VNodeChild} from 'vue'
 import {MountingOptions} from '@vue/test-utils'
 import {queries, EventType, BoundFunctions} from '@testing-library/dom'
 // eslint-disable-next-line import/no-extraneous-dependencies
 import {OptionsReceived as PrettyFormatOptions} from 'pretty-format'
+import {ComponentProps, ComponentSlots} from 'vue-component-type-helpers'
+import {RemoveIndexSignature} from 'type-fest'
 
 // NOTE: fireEvent is overridden below
 export * from '@testing-library/dom'
@@ -44,12 +47,26 @@ interface VueTestingLibraryRenderOptions {
   container?: Element
   baseElement?: Element
 }
-export type RenderOptions = VueTestingLibraryRenderOptions &
-  VueTestUtilsRenderOptions
 
-export function render(
-  TestComponent: any, // this makes me sad :sob:
-  options?: RenderOptions,
+type AllowNonFunctionSlots<Slots> = {
+  [K in keyof Slots]: Slots[K] | VNodeChild
+}
+type ExtractSlots<C> = AllowNonFunctionSlots<
+  Partial<RemoveIndexSignature<ComponentSlots<C>>>
+>
+
+export interface RenderOptions<C>
+  extends Omit<
+    VueTestingLibraryRenderOptions & VueTestUtilsRenderOptions,
+    'props' | 'slots'
+  > {
+  props?: ComponentProps<C>
+  slots?: ExtractSlots<C>
+}
+
+export function render<C>(
+  TestComponent: C,
+  options?: RenderOptions<C>,
 ): RenderResult
 
 export type AsyncFireObject = {
diff --git a/types/index.test-d.ts b/types/index.test-d.ts
index 5a0253d..02e9e18 100644
--- a/types/index.test-d.ts
+++ b/types/index.test-d.ts
@@ -68,7 +68,7 @@ export async function testWaitFor() {
 export function testOptions() {
   render(SomeComponent, {
     attrs: {a: 1},
-    props: {c: 1}, // ideally it would fail because `c` is not an existing prop…
+    props: {foo: 1},
     data: () => ({b: 2}),
     slots: {
       default: '<div />',