]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compile-sfc): handle mapped types work with omit and pick (#12648)
authoredison <daiwei521@126.com>
Thu, 5 Jun 2025 02:01:22 +0000 (10:01 +0800)
committerGitHub <noreply@github.com>
Thu, 5 Jun 2025 02:01:22 +0000 (10:01 +0800)
close #12647

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

index 4ced9b8879a2280c35f1cf328f0db4c98e628ef5..68fc5cc3159731e2cbd2b84b9c16a356bd6b6374 100644 (file)
@@ -278,6 +278,23 @@ describe('resolveType', () => {
     })
   })
 
+  test('utility type: mapped type with Omit and Pick', () => {
+    expect(
+      resolve(`
+      type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
+      interface Test {
+        foo: string;
+        bar?: string;
+      }
+      type OptionalTest = Optional<Test, 'foo'>
+      defineProps<OptionalTest>()
+    `).props,
+    ).toStrictEqual({
+      foo: ['String'],
+      bar: ['String'],
+    })
+  })
+
   test('utility type: ReadonlyArray', () => {
     expect(
       resolve(`
index 3507a783c762e82add6204b9e140b3c75386d4e8..85832dfc39a02128c28a081fbfd80729a159e9b9 100644 (file)
@@ -546,26 +546,43 @@ function resolveStringType(
   ctx: TypeResolveContext,
   node: Node,
   scope: TypeScope,
+  typeParameters?: Record<string, Node>,
 ): string[] {
   switch (node.type) {
     case 'StringLiteral':
       return [node.value]
     case 'TSLiteralType':
-      return resolveStringType(ctx, node.literal, scope)
+      return resolveStringType(ctx, node.literal, scope, typeParameters)
     case 'TSUnionType':
-      return node.types.map(t => resolveStringType(ctx, t, scope)).flat()
+      return node.types
+        .map(t => resolveStringType(ctx, t, scope, typeParameters))
+        .flat()
     case 'TemplateLiteral': {
       return resolveTemplateKeys(ctx, node, scope)
     }
     case 'TSTypeReference': {
       const resolved = resolveTypeReference(ctx, node, scope)
       if (resolved) {
-        return resolveStringType(ctx, resolved, scope)
+        return resolveStringType(ctx, resolved, scope, typeParameters)
       }
       if (node.typeName.type === 'Identifier') {
+        const name = node.typeName.name
+        if (typeParameters && typeParameters[name]) {
+          return resolveStringType(
+            ctx,
+            typeParameters[name],
+            scope,
+            typeParameters,
+          )
+        }
         const getParam = (index = 0) =>
-          resolveStringType(ctx, node.typeParameters!.params[index], scope)
-        switch (node.typeName.name) {
+          resolveStringType(
+            ctx,
+            node.typeParameters!.params[index],
+            scope,
+            typeParameters,
+          )
+        switch (name) {
           case 'Extract':
             return getParam(1)
           case 'Exclude': {
@@ -671,6 +688,7 @@ function resolveBuiltin(
         ctx,
         node.typeParameters!.params[1],
         scope,
+        typeParameters,
       )
       const res: ResolvedElements = { props: {}, calls: t.calls }
       for (const key of picked) {
@@ -683,6 +701,7 @@ function resolveBuiltin(
         ctx,
         node.typeParameters!.params[1],
         scope,
+        typeParameters,
       )
       const res: ResolvedElements = { props: {}, calls: t.calls }
       for (const key in t.props) {