]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): unwrap TS node for defineProps (#7340)
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Tue, 28 Mar 2023 07:22:01 +0000 (15:22 +0800)
committerGitHub <noreply@github.com>
Tue, 28 Mar 2023 07:22:01 +0000 (15:22 +0800)
packages/compiler-core/src/babelUtils.ts
packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript.spec.ts
packages/compiler-sfc/src/compileScript.ts

index e773015f90f82da90ceb3045bb18fc1351a7630b..5ddbc1ea4124444200ba7c56742c8166c99517a4 100644 (file)
@@ -38,9 +38,7 @@ export function walkIdentifiers(
       if (
         parent &&
         parent.type.startsWith('TS') &&
-        parent.type !== 'TSAsExpression' &&
-        parent.type !== 'TSNonNullExpression' &&
-        parent.type !== 'TSTypeAssertion'
+        !TS_NODE_TYPES.includes(parent.type)
       ) {
         return this.skip()
       }
@@ -422,3 +420,18 @@ function isReferenced(node: Node, parent: Node, grandparent?: Node): boolean {
 
   return true
 }
+
+export const TS_NODE_TYPES = [
+  'TSAsExpression', // foo as number
+  'TSTypeAssertion', // (<number>foo)
+  'TSNonNullExpression', // foo!
+  'TSInstantiationExpression', // foo<string>
+  'TSSatisfiesExpression' // foo satisfies T
+]
+export function unwrapTSNode(node: Node): Node {
+  if (TS_NODE_TYPES.includes(node.type)) {
+    return unwrapTSNode((node as any).expression)
+  } else {
+    return node
+  }
+}
index 879790e16fa3594001557b5ef07a7181e0ffd0b6..05e5e4fd1fd0e919f2055229a068ab84eb4b47be 100644 (file)
@@ -1486,6 +1486,22 @@ return { emit }
 })"
 `;
 
+exports[`SFC compile <script setup> > with TypeScript > defineProps w/ TS assertion 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+  props: ['foo'],
+  setup(__props, { expose }) {
+  expose();
+
+        
+      
+return {  }
+}
+
+})"
+`;
+
 exports[`SFC compile <script setup> > with TypeScript > defineProps w/ exported interface 1`] = `
 "import { defineComponent as _defineComponent } from 'vue'
 export interface Props { x?: number }
index 5fb90b475e682d2ca3cada9968979cda07ceadc9..9c3c4a7027388ab3a35ce5024925ab9f9edfd46d 100644 (file)
@@ -1145,6 +1145,19 @@ const emit = defineEmits(['a', 'b'])
       })
     })
 
+    test('defineProps w/ TS assertion', () => {
+      const { content, bindings } = compile(`
+      <script setup lang="ts">
+        defineProps(['foo'])! as any
+      </script>
+    `)
+      expect(content).toMatch(`props: ['foo']`)
+      assertCode(content)
+      expect(bindings).toStrictEqual({
+        foo: BindingTypes.PROPS
+      })
+    })
+
     test('withDefaults (static)', () => {
       const { content, bindings } = compile(`
       <script setup lang="ts">
index 278a433db3881ab303d42604cbdf4525ac75d042..1b13c90b6eefaacf71ea6e0612b5c14a56d28b7d 100644 (file)
@@ -9,7 +9,8 @@ import {
   UNREF,
   SimpleExpressionNode,
   isFunctionType,
-  walkIdentifiers
+  walkIdentifiers,
+  unwrapTSNode
 } from '@vue/compiler-dom'
 import { DEFAULT_FILENAME, SFCDescriptor, SFCScriptBlock } from './parse'
 import {
@@ -1229,17 +1230,18 @@ export function compileScript(
     }
 
     if (node.type === 'ExpressionStatement') {
+      const expr = unwrapTSNode(node.expression)
       // process `defineProps` and `defineEmit(s)` calls
       if (
-        processDefineProps(node.expression) ||
-        processDefineEmits(node.expression) ||
-        processDefineOptions(node.expression) ||
-        processWithDefaults(node.expression)
+        processDefineProps(expr) ||
+        processDefineEmits(expr) ||
+        processDefineOptions(expr) ||
+        processWithDefaults(expr)
       ) {
         s.remove(node.start! + startOffset, node.end! + startOffset)
-      } else if (processDefineExpose(node.expression)) {
+      } else if (processDefineExpose(expr)) {
         // defineExpose({}) -> expose({})
-        const callee = (node.expression as CallExpression).callee
+        const callee = (expr as CallExpression).callee
         s.overwrite(
           callee.start! + startOffset,
           callee.end! + startOffset,
@@ -1253,8 +1255,9 @@ export function compileScript(
       let left = total
       for (let i = 0; i < total; i++) {
         const decl = node.declarations[i]
-        if (decl.init) {
-          if (processDefineOptions(decl.init)) {
+        const init = decl.init && unwrapTSNode(decl.init)
+        if (init) {
+          if (processDefineOptions(init)) {
             error(
               `${DEFINE_OPTIONS}() has no returning value, it cannot be assigned.`,
               node
@@ -1263,9 +1266,9 @@ export function compileScript(
 
           // defineProps / defineEmits
           const isDefineProps =
-            processDefineProps(decl.init, decl.id, node.kind) ||
-            processWithDefaults(decl.init, decl.id, node.kind)
-          const isDefineEmits = processDefineEmits(decl.init, decl.id)
+            processDefineProps(init, decl.id, node.kind) ||
+            processWithDefaults(init, decl.id, node.kind)
+          const isDefineEmits = processDefineEmits(init, decl.id)
           if (isDefineProps || isDefineEmits) {
             if (left === 1) {
               s.remove(node.start! + startOffset, node.end! + startOffset)
@@ -1801,7 +1804,8 @@ function walkDeclaration(
       )
 
     // export const foo = ...
-    for (const { id, init } of node.declarations) {
+    for (const { id, init: _init } of node.declarations) {
+      const init = _init && unwrapTSNode(_init)
       const isDefineCall = !!(
         isConst &&
         isCallOf(