]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): support as keyword with template literal types (#11100)
authorZhaolin Liang <liangzhaolin0304@outlook.com>
Mon, 10 Jun 2024 07:19:39 +0000 (15:19 +0800)
committerGitHub <noreply@github.com>
Mon, 10 Jun 2024 07:19:39 +0000 (15:19 +0800)
close #10962

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

index 697227794b007f74757b46da3541eb9e8151d549..5dd02a66d3f7698e4cc52bbaecf6e9f9a0d5338f 100644 (file)
@@ -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<T extends string, V> = {
+        [K in Breakpoints as \`\${T}\${Capitalize<K>}\`]: V
+      }
+      type ColsBreakpoints = BreakpointFactory<'cols', number>
+      defineProps<ColsBreakpoints>()
+      `)
+      expect(props).toStrictEqual({
+        colsSm: ['Number'],
+        colsMd: ['Number'],
+        colsLg: ['Number'],
+      })
+    })
+  })
 })
 
 function resolve(
index f5cac0fbb2943e86806c68b479fd6d873b8049b6..5566744526a577f3f6c1245cc9701560f2ebef1c 100644 (file)
@@ -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<string, Node>,
 ): 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(
       {