From 5ac1813f7c9fde4bc9c3c0f1fe6809e1342deb68 Mon Sep 17 00:00:00 2001 From: lzl0304 Date: Mon, 10 Jun 2024 12:42:27 +0800 Subject: [PATCH] fix(compiler-sfc): support as keyword with template literal types --- .../compileScript/resolveType.spec.ts | 31 +++++++++++++++++++ .../compiler-sfc/src/script/resolveType.ts | 13 ++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts index 697227794b0..5dd02a66d3f 100644 --- a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts @@ -1198,6 +1198,37 @@ describe('resolveType', () => { }) }) }) + + describe('template literals', () => { + test('mapped types with string type', () => { + expect( + resolve(` + type X = 'a' | 'b' + defineProps<{[K in X as \`\${K}_foo\`]: string}>() + `).props, + ).toStrictEqual({ + a_foo: ['String'], + b_foo: ['String'], + }) + }) + + // #10962 + test('mapped types with generic parameters', () => { + const { props } = resolve(` + type Breakpoints = 'sm' | 'md' | 'lg' + type BreakpointFactory = { + [K in Breakpoints as \`\${T}\${Capitalize}\`]: V + } + type ColsBreakpoints = BreakpointFactory<'cols', number> + defineProps() + `) + expect(props).toStrictEqual({ + colsSm: ['Number'], + colsMd: ['Number'], + colsLg: ['Number'], + }) + }) + }) }) function resolve( diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts index f5cac0fbb29..5566744526a 100644 --- a/packages/compiler-sfc/src/script/resolveType.ts +++ b/packages/compiler-sfc/src/script/resolveType.ts @@ -188,7 +188,7 @@ function innerResolveTypeElements( node.type, ) case 'TSMappedType': - return resolveMappedType(ctx, node, scope) + return resolveMappedType(ctx, node, scope, typeParameters) case 'TSIndexedAccessType': { const types = resolveIndexType(ctx, node, scope) return mergeElements( @@ -450,9 +450,18 @@ function resolveMappedType( ctx: TypeResolveContext, node: TSMappedType, scope: TypeScope, + typeParameters?: Record, ): ResolvedElements { const res: ResolvedElements = { props: {} } - const keys = resolveStringType(ctx, node.typeParameter.constraint!, scope) + let keys: string[] + if (node.nameType) { + const { name, constraint } = node.typeParameter + scope = createChildScope(scope) + Object.assign(scope.types, { ...typeParameters, [name]: constraint }) + keys = resolveStringType(ctx, node.nameType, scope) + } else { + keys = resolveStringType(ctx, node.typeParameter.constraint!, scope) + } for (const key of keys) { res.props[key] = createProperty( {