Ver Fonte

fix(compiler-sfc): infer Vue ref wrapper types when source is unresolvable (#14758)

close #14729
Ashish kumar choubey há 1 mês atrás
pai
commit
7f46fd411b

+ 55 - 0
packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts

@@ -803,6 +803,61 @@ describe('resolveType', () => {
         foo: ['Boolean', 'Symbol', 'Number'],
       })
     })
+
+    // #14729 — original user repro shape
+    test('MaybeRef wrapped array type in interface inheritance chain', () => {
+      expect(
+        resolve(`
+        import type { MaybeRef } from 'unresolvable-pkg-xyz'
+        type OptionItem = { label: string; value: string | number }
+        type FormItemOptions<T = any, C = any> =
+          | MaybeRef<OptionItem[]>
+          | Promise<OptionItem[]>
+          | ((row: T, context: C) => OptionItem[] | Promise<OptionItem[]>)
+        interface ISelectable<T = any, C = any> {
+          options?: FormItemOptions<T, C>
+        }
+        interface XSelectProps<T = any, C = any> extends ISelectable<T, C> {
+          modelValue?: unknown
+        }
+        defineProps<XSelectProps>()
+      `).props,
+      ).toMatchObject({
+        // 'Array' must be present so that array values pass runtime type check
+        options: expect.arrayContaining(['Array', 'Promise', 'Function']),
+      })
+    })
+
+    // #14729
+    test('Vue ref wrapper types in union are inferred when source is unresolvable', () => {
+      expect(
+        resolve(`
+        import type {
+          MaybeRef,
+          Ref,
+          ShallowRef,
+          ComputedRef,
+          WritableComputedRef,
+          MaybeRefOrGetter,
+        } from 'unresolvable-pkg-xyz'
+        defineProps<{
+          a?: MaybeRef<string[]> | Promise<string[]> | (() => string[])
+          b?: Ref<number>
+          c?: ShallowRef<number>
+          d?: ComputedRef<number>
+          e?: WritableComputedRef<number>
+          f?: MaybeRefOrGetter<boolean>
+        }>()
+      `).props,
+      ).toStrictEqual({
+        a: ['Object', 'Array', 'Promise', 'Function'],
+        b: ['Object'],
+        c: ['Object'],
+        d: ['Object'],
+        e: ['Object'],
+        f: ['Object', 'Function', 'Boolean'],
+      })
+    })
   })
 
   describe('generics', () => {

+ 35 - 1
packages/compiler-sfc/src/script/resolveType.ts

@@ -1727,7 +1727,13 @@ export function inferRuntimeType(
         }
 
       case 'TSTypeReference': {
-        const resolved = resolveTypeReference(ctx, node, scope)
+        // #14729 — if resolution fails (e.g. an unresolvable import), still
+        // fall through to the built-in name handling below so that well-known
+        // types like Ref/MaybeRef/Promise can be inferred from the name alone.
+        let resolved: ScopeTypeNode | undefined
+        try {
+          resolved = resolveTypeReference(ctx, node, scope)
+        } catch {}
         if (resolved) {
           if (resolved.type === 'TSTypeAliasDeclaration') {
             // #13240
@@ -1859,6 +1865,34 @@ export function inferRuntimeType(
               case 'ReadonlySet':
                 return ['Set']
 
+              // Vue ref wrapper types — handled here so that runtime type
+              // inference still works when `vue` types cannot be resolved
+              // (e.g. consumed as built artifacts in another package). #14729
+              case 'Ref':
+              case 'ShallowRef':
+              case 'ComputedRef':
+              case 'WritableComputedRef':
+                return ['Object']
+              case 'MaybeRef':
+              case 'MaybeRefOrGetter': {
+                const types = new Set<string>(['Object'])
+                if (node.typeName.name === 'MaybeRefOrGetter') {
+                  types.add('Function')
+                }
+                if (node.typeParameters && node.typeParameters.params[0]) {
+                  for (const t of inferRuntimeType(
+                    ctx,
+                    node.typeParameters.params[0],
+                    scope,
+                    false,
+                    typeParameters,
+                  )) {
+                    types.add(t)
+                  }
+                }
+                return Array.from(types)
+              }
+
               case 'NonNullable':
                 if (node.typeParameters && node.typeParameters.params[0]) {
                   return inferRuntimeType(