diff --git a/.changeset/modern-dancers-explode.md b/.changeset/modern-dancers-explode.md
new file mode 100644
index 000000000..dc9e0e0c4
--- /dev/null
+++ b/.changeset/modern-dancers-explode.md
@@ -0,0 +1,5 @@
+---
+"@vue-macros/volar": patch
+---
+
+support generic component for export-expose
diff --git a/packages/volar/src/common.ts b/packages/volar/src/common.ts
index d8d7b3f64..674558625 100644
--- a/packages/volar/src/common.ts
+++ b/packages/volar/src/common.ts
@@ -34,6 +34,13 @@ export function addEmits(content: Code[], decl: Code[]) {
return true
}
+export function addCode(codes: Code[], ...args: Code[]) {
+ const index = codes.findIndex((code) =>
+ code.includes('__VLS_setup = (async () => {'),
+ )
+ codes.splice(index > -1 ? index + 1 : codes.length, 0, ...args)
+}
+
export function getVolarOptions(
vueCompilerOptions: VueCompilerOptions,
): VolarOptions | undefined {
diff --git a/packages/volar/src/export-expose.ts b/packages/volar/src/export-expose.ts
index 77fdc2f7c..f29c047d1 100644
--- a/packages/volar/src/export-expose.ts
+++ b/packages/volar/src/export-expose.ts
@@ -3,11 +3,11 @@ import {
type Sfc,
type VueLanguagePlugin,
allCodeFeatures,
- replaceAll,
+ replace,
replaceSourceRange,
} from '@vue/language-core'
import { createFilter } from '@rollup/pluginutils'
-import { getStart, getVolarOptions } from './common'
+import { addCode, getStart, getVolarOptions } from './common'
import type { VolarOptions } from '..'
function transform(options: {
@@ -142,13 +142,21 @@ function transform(options: {
',\n',
])
- replaceAll(
- codes,
- /return {\n/g,
- 'return {\n...{ ',
- ...exposedStrings,
- ' },\n',
- )
+ if (sfc.scriptSetup?.generic) {
+ addCode(codes, `const __VLS_exportExposed = {\n`, ...exposedStrings, `};\n`)
+
+ replace(
+ codes,
+ /(?<=expose\(exposed: import\(\S+\)\.ShallowUnwrapRef<)/,
+ 'typeof __VLS_exportExposed & ',
+ )
+ } else {
+ replace(
+ codes,
+ /(?<=export\sdefault \(await import\(\S+\)\)\.defineComponent\({[\S\s]*setup\(\) {\nreturn {\n)/,
+ ...exposedStrings,
+ )
+ }
}
const plugin: VueLanguagePlugin = ({
diff --git a/packages/volar/src/jsx-directive/context.ts b/packages/volar/src/jsx-directive/context.ts
index f5c949c1f..ba776e5a0 100644
--- a/packages/volar/src/jsx-directive/context.ts
+++ b/packages/volar/src/jsx-directive/context.ts
@@ -1,4 +1,4 @@
-import { getText, isJsxExpression } from '../common'
+import { addCode, getText, isJsxExpression } from '../common'
import {
type JsxDirective,
type TransformOptions,
@@ -11,7 +11,7 @@ export function transformCtx(
index: number,
options: TransformOptions,
) {
- const { ts, codes, sfc } = options
+ const { ts, codes } = options
const openingElement = getOpeningElement(node, options)
if (!openingElement) return ''
@@ -39,15 +39,10 @@ export function transformCtx(
)
}
- const code = `const ${ctxName} = __VLS_getFunctionalComponentCtx(${tagName}, __VLS_asFunctionalComponent(${tagName})({${props}}));\n`
- if (sfc.scriptSetup?.generic) {
- const index = codes.findIndex((code) =>
- code.includes('__VLS_setup = (async () => {'),
- )
- codes.splice(index + 1, 0, code)
- } else {
- codes.push(code)
- }
+ addCode(
+ codes,
+ `const ${ctxName} = __VLS_getFunctionalComponentCtx(${tagName}, __VLS_asFunctionalComponent(${tagName})({${props}}));\n`,
+ )
return ctxName
}
diff --git a/playground/vue3/src/examples/export-expose/child-generic.vue b/playground/vue3/src/examples/export-expose/child-generic.vue
new file mode 100644
index 000000000..63271c8bc
--- /dev/null
+++ b/playground/vue3/src/examples/export-expose/child-generic.vue
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/playground/vue3/src/examples/export-expose/index.vue b/playground/vue3/src/examples/export-expose/index.vue
index caec61fd5..3feb9bed1 100644
--- a/playground/vue3/src/examples/export-expose/index.vue
+++ b/playground/vue3/src/examples/export-expose/index.vue
@@ -2,12 +2,15 @@
import { ref } from 'vue'
import { Assert } from '../../assert'
import Child from './child.vue'
+import ChildGeneric from './child-generic.vue'
const child = ref>()
+const childGeneric = ref>()
+
-
+
diff --git a/playground/vue3/src/vite-env.d.ts b/playground/vue3/src/vite-env.d.ts
index f96dbf9bf..f5fe0eb78 100644
--- a/playground/vue3/src/vite-env.d.ts
+++ b/playground/vue3/src/vite-env.d.ts
@@ -1,2 +1,13 @@
///
///
+
+declare type ComponentExposed = T extends new (...args: any) => infer E
+ ? E
+ : T extends (
+ props: any,
+ ctx: any,
+ expose: (exposed: infer E) => any,
+ ...args: any
+ ) => any
+ ? NonNullable
+ : any