From 8df75d64c5fa08de0049017fc3a5e04db1bd082c Mon Sep 17 00:00:00 2001 From: daiwei Date: Thu, 4 Sep 2025 22:44:22 +0800 Subject: [PATCH 1/2] fix(compiler-sfc): enhance inferRuntimeType to support TSMappedType with indexed access only for the strict pattern {[K in keyof T]: T[K]} close #13847 --- .../compiler-sfc/src/script/resolveType.ts | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts index fb79323cbb4..0677a4fb6b5 100644 --- a/packages/compiler-sfc/src/script/resolveType.ts +++ b/packages/compiler-sfc/src/script/resolveType.ts @@ -1781,6 +1781,47 @@ export function inferRuntimeType( typeParameters, ).filter(t => t !== UNKNOWN_TYPE) } + case 'TSMappedType': { + // only support { [K in keyof T]: T[K] } + const { typeAnnotation, typeParameter } = node + if ( + typeAnnotation && + typeAnnotation.type === 'TSIndexedAccessType' && + typeParameter && + typeParameter.constraint && + typeParameters + ) { + const constraint = typeParameter.constraint + if ( + constraint.type === 'TSTypeOperator' && + constraint.operator === 'keyof' && + constraint.typeAnnotation && + constraint.typeAnnotation.type === 'TSTypeReference' && + constraint.typeAnnotation.typeName.type === 'Identifier' + ) { + const typeName = constraint.typeAnnotation.typeName.name + const index = typeAnnotation.indexType + const obj = typeAnnotation.objectType + if ( + obj && + obj.type === 'TSTypeReference' && + obj.typeName.type === 'Identifier' && + obj.typeName.name === typeName && + index && + index.type === 'TSTypeReference' && + index.typeName.type === 'Identifier' && + index.typeName.name === typeParameter.name + ) { + const targetType = typeParameters[typeName] + if (targetType) { + return inferRuntimeType(ctx, targetType, scope) + } + } + } + } + + return [UNKNOWN_TYPE] + } case 'TSEnumDeclaration': return inferEnumType(node) From 99bbec5e8d20a4009f1c79892e33f3745770c657 Mon Sep 17 00:00:00 2001 From: daiwei Date: Thu, 4 Sep 2025 22:53:42 +0800 Subject: [PATCH 2/2] test: add test --- .../__tests__/compileScript/resolveType.spec.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts index a1476c76a82..5515a19f601 100644 --- a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts @@ -731,6 +731,22 @@ describe('resolveType', () => { }) }) + test('TSMappedType with indexed access', () => { + const { props } = resolve( + ` + type Prettify = { [K in keyof T]: T[K] } & {} + type Side = 'top' | 'right' | 'bottom' | 'left' + type AlignedPlacement = \`\${Side}-\${Alignment}\` + type Alignment = 'start' | 'end' + type Placement = Prettify + defineProps<{placement?: Placement}>() + `, + ) + expect(props).toStrictEqual({ + placement: ['String', 'Object'], + }) + }) + describe('type alias declaration', () => { // #13240 test('function type', () => {