mirror of https://github.com/vuejs/core.git
fix(compiler-sfc): fix type resolution for shared type w/ different generic parameters
close #9871
This commit is contained in:
parent
1b522cae07
commit
a8d0b1b38b
|
@ -939,6 +939,34 @@ describe('resolveType', () => {
|
|||
manufacturer: ['Object']
|
||||
})
|
||||
})
|
||||
|
||||
// #9871
|
||||
test('shared generics with different args', () => {
|
||||
const files = {
|
||||
'/foo.ts': `export interface Foo<T> { value: T }`
|
||||
}
|
||||
const { props } = resolve(
|
||||
`import type { Foo } from './foo'
|
||||
defineProps<Foo<string>>()`,
|
||||
files,
|
||||
undefined,
|
||||
`/One.vue`
|
||||
)
|
||||
expect(props).toStrictEqual({
|
||||
value: ['String']
|
||||
})
|
||||
const { props: props2 } = resolve(
|
||||
`import type { Foo } from './foo'
|
||||
defineProps<Foo<number>>()`,
|
||||
files,
|
||||
undefined,
|
||||
`/Two.vue`,
|
||||
false /* do not invalidate cache */
|
||||
)
|
||||
expect(props2).toStrictEqual({
|
||||
value: ['Number']
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
|
@ -1012,7 +1040,8 @@ function resolve(
|
|||
code: string,
|
||||
files: Record<string, string> = {},
|
||||
options?: Partial<SFCScriptCompileOptions>,
|
||||
sourceFileName: string = '/Test.vue'
|
||||
sourceFileName: string = '/Test.vue',
|
||||
invalidateCache = true
|
||||
) {
|
||||
const { descriptor } = parse(`<script setup lang="ts">\n${code}\n</script>`, {
|
||||
filename: sourceFileName
|
||||
|
@ -1030,8 +1059,10 @@ function resolve(
|
|||
...options
|
||||
})
|
||||
|
||||
for (const file in files) {
|
||||
invalidateTypeCache(file)
|
||||
if (invalidateCache) {
|
||||
for (const file in files) {
|
||||
invalidateTypeCache(file)
|
||||
}
|
||||
}
|
||||
|
||||
// ctx.userImports is collected when calling compileScript(), but we are
|
||||
|
|
|
@ -90,7 +90,7 @@ export class TypeScope {
|
|||
public types: Record<string, ScopeTypeNode> = Object.create(null),
|
||||
public declares: Record<string, ScopeTypeNode> = Object.create(null)
|
||||
) {}
|
||||
|
||||
isGenericScope = false
|
||||
resolvedImportSources: Record<string, string> = Object.create(null)
|
||||
exportedTypes: Record<string, ScopeTypeNode> = Object.create(null)
|
||||
exportedDeclares: Record<string, ScopeTypeNode> = Object.create(null)
|
||||
|
@ -121,15 +121,17 @@ export function resolveTypeElements(
|
|||
scope?: TypeScope,
|
||||
typeParameters?: Record<string, Node>
|
||||
): ResolvedElements {
|
||||
if (node._resolvedElements) {
|
||||
const canCache = !typeParameters
|
||||
if (canCache && node._resolvedElements) {
|
||||
return node._resolvedElements
|
||||
}
|
||||
return (node._resolvedElements = innerResolveTypeElements(
|
||||
const resolved = innerResolveTypeElements(
|
||||
ctx,
|
||||
node,
|
||||
node._ownerScope || scope || ctxToScope(ctx),
|
||||
typeParameters
|
||||
))
|
||||
)
|
||||
return canCache ? (node._resolvedElements = resolved) : resolved
|
||||
}
|
||||
|
||||
function innerResolveTypeElements(
|
||||
|
@ -190,17 +192,18 @@ function innerResolveTypeElements(
|
|||
}
|
||||
const resolved = resolveTypeReference(ctx, node, scope)
|
||||
if (resolved) {
|
||||
const typeParams: Record<string, Node> = Object.create(null)
|
||||
let typeParams: Record<string, Node> | undefined
|
||||
if (
|
||||
(resolved.type === 'TSTypeAliasDeclaration' ||
|
||||
resolved.type === 'TSInterfaceDeclaration') &&
|
||||
resolved.typeParameters &&
|
||||
node.typeParameters
|
||||
) {
|
||||
typeParams = Object.create(null)
|
||||
resolved.typeParameters.params.forEach((p, i) => {
|
||||
let param = typeParameters && typeParameters[p.name]
|
||||
if (!param) param = node.typeParameters!.params[i]
|
||||
typeParams[p.name] = param
|
||||
typeParams![p.name] = param
|
||||
})
|
||||
}
|
||||
return resolveTypeElements(
|
||||
|
@ -297,6 +300,7 @@ function typeElementsToMap(
|
|||
// capture generic parameters on node's scope
|
||||
if (typeParameters) {
|
||||
scope = createChildScope(scope)
|
||||
scope.isGenericScope = true
|
||||
Object.assign(scope.types, typeParameters)
|
||||
}
|
||||
;(e as MaybeWithScope)._ownerScope = scope
|
||||
|
@ -669,16 +673,18 @@ function resolveTypeReference(
|
|||
name?: string,
|
||||
onlyExported = false
|
||||
): ScopeTypeNode | undefined {
|
||||
if (node._resolvedReference) {
|
||||
const canCache = !scope?.isGenericScope
|
||||
if (canCache && node._resolvedReference) {
|
||||
return node._resolvedReference
|
||||
}
|
||||
return (node._resolvedReference = innerResolveTypeReference(
|
||||
const resolved = innerResolveTypeReference(
|
||||
ctx,
|
||||
scope || ctxToScope(ctx),
|
||||
name || getReferenceName(node),
|
||||
node,
|
||||
onlyExported
|
||||
))
|
||||
)
|
||||
return canCache ? (node._resolvedReference = resolved) : resolved
|
||||
}
|
||||
|
||||
function innerResolveTypeReference(
|
||||
|
|
Loading…
Reference in New Issue