Skip to content

Commit 7f46fd4

Browse files
authored
fix(compiler-sfc): infer Vue ref wrapper types when source is unresolvable (#14758)
close #14729
1 parent acfffe3 commit 7f46fd4

2 files changed

Lines changed: 90 additions & 1 deletion

File tree

packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,61 @@ describe('resolveType', () => {
803803
foo: ['Boolean', 'Symbol', 'Number'],
804804
})
805805
})
806+
807+
// #14729 — original user repro shape
808+
test('MaybeRef wrapped array type in interface inheritance chain', () => {
809+
expect(
810+
resolve(`
811+
import type { MaybeRef } from 'unresolvable-pkg-xyz'
812+
type OptionItem = { label: string; value: string | number }
813+
type FormItemOptions<T = any, C = any> =
814+
| MaybeRef<OptionItem[]>
815+
| Promise<OptionItem[]>
816+
| ((row: T, context: C) => OptionItem[] | Promise<OptionItem[]>)
817+
interface ISelectable<T = any, C = any> {
818+
options?: FormItemOptions<T, C>
819+
}
820+
interface XSelectProps<T = any, C = any> extends ISelectable<T, C> {
821+
modelValue?: unknown
822+
}
823+
defineProps<XSelectProps>()
824+
`).props,
825+
).toMatchObject({
826+
// 'Array' must be present so that array values pass runtime type check
827+
options: expect.arrayContaining(['Array', 'Promise', 'Function']),
828+
})
829+
})
830+
831+
// #14729
832+
test('Vue ref wrapper types in union are inferred when source is unresolvable', () => {
833+
expect(
834+
resolve(`
835+
import type {
836+
MaybeRef,
837+
Ref,
838+
ShallowRef,
839+
ComputedRef,
840+
WritableComputedRef,
841+
MaybeRefOrGetter,
842+
} from 'unresolvable-pkg-xyz'
843+
defineProps<{
844+
a?: MaybeRef<string[]> | Promise<string[]> | (() => string[])
845+
b?: Ref<number>
846+
c?: ShallowRef<number>
847+
d?: ComputedRef<number>
848+
e?: WritableComputedRef<number>
849+
f?: MaybeRefOrGetter<boolean>
850+
}>()
851+
`).props,
852+
).toStrictEqual({
853+
a: ['Object', 'Array', 'Promise', 'Function'],
854+
b: ['Object'],
855+
c: ['Object'],
856+
d: ['Object'],
857+
e: ['Object'],
858+
f: ['Object', 'Function', 'Boolean'],
859+
})
860+
})
806861
})
807862

808863
describe('generics', () => {

packages/compiler-sfc/src/script/resolveType.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1727,7 +1727,13 @@ export function inferRuntimeType(
17271727
}
17281728

17291729
case 'TSTypeReference': {
1730-
const resolved = resolveTypeReference(ctx, node, scope)
1730+
// #14729 — if resolution fails (e.g. an unresolvable import), still
1731+
// fall through to the built-in name handling below so that well-known
1732+
// types like Ref/MaybeRef/Promise can be inferred from the name alone.
1733+
let resolved: ScopeTypeNode | undefined
1734+
try {
1735+
resolved = resolveTypeReference(ctx, node, scope)
1736+
} catch {}
17311737
if (resolved) {
17321738
if (resolved.type === 'TSTypeAliasDeclaration') {
17331739
// #13240
@@ -1859,6 +1865,34 @@ export function inferRuntimeType(
18591865
case 'ReadonlySet':
18601866
return ['Set']
18611867

1868+
// Vue ref wrapper types — handled here so that runtime type
1869+
// inference still works when `vue` types cannot be resolved
1870+
// (e.g. consumed as built artifacts in another package). #14729
1871+
case 'Ref':
1872+
case 'ShallowRef':
1873+
case 'ComputedRef':
1874+
case 'WritableComputedRef':
1875+
return ['Object']
1876+
case 'MaybeRef':
1877+
case 'MaybeRefOrGetter': {
1878+
const types = new Set<string>(['Object'])
1879+
if (node.typeName.name === 'MaybeRefOrGetter') {
1880+
types.add('Function')
1881+
}
1882+
if (node.typeParameters && node.typeParameters.params[0]) {
1883+
for (const t of inferRuntimeType(
1884+
ctx,
1885+
node.typeParameters.params[0],
1886+
scope,
1887+
false,
1888+
typeParameters,
1889+
)) {
1890+
types.add(t)
1891+
}
1892+
}
1893+
return Array.from(types)
1894+
}
1895+
18621896
case 'NonNullable':
18631897
if (node.typeParameters && node.typeParameters.params[0]) {
18641898
return inferRuntimeType(

0 commit comments

Comments
 (0)