]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): ensure script setup generates type-valid ts output
authorEvan You <yyx990803@gmail.com>
Thu, 2 Sep 2021 15:51:41 +0000 (11:51 -0400)
committerEvan You <yyx990803@gmail.com>
Thu, 2 Sep 2021 15:51:41 +0000 (11:51 -0400)
fix #4455

packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript.spec.ts
packages/compiler-sfc/src/compileScript.ts

index 9e63ee1a42c439fee444a3d023ddf85c4f563dbf..b3ffe8e2c1a18d958296eae4b0d6f53bd57dff5d 100644 (file)
@@ -704,7 +704,7 @@ exports[`SFC compile <script setup> with TypeScript defineEmits w/ type (exporte
 export interface Emits { (e: 'foo' | 'bar'): void }
       
 export default /*#__PURE__*/_defineComponent({
-  emits: [\\"foo\\", \\"bar\\"] as unknown as undefined,
+  emits: [\\"foo\\", \\"bar\\"],
   setup(__props, { expose, emit }: { emit: ({ (e: 'foo' | 'bar'): void }), expose: any, slots: any, attrs: any }) {
   expose()
 
@@ -721,7 +721,7 @@ exports[`SFC compile <script setup> with TypeScript defineEmits w/ type (exporte
 export type Emits = { (e: 'foo' | 'bar'): void }
       
 export default /*#__PURE__*/_defineComponent({
-  emits: [\\"foo\\", \\"bar\\"] as unknown as undefined,
+  emits: [\\"foo\\", \\"bar\\"],
   setup(__props, { expose, emit }: { emit: ({ (e: 'foo' | 'bar'): void }), expose: any, slots: any, attrs: any }) {
   expose()
 
@@ -738,7 +738,7 @@ exports[`SFC compile <script setup> with TypeScript defineEmits w/ type (interfa
 interface Emits { (e: 'foo' | 'bar'): void }
       
 export default /*#__PURE__*/_defineComponent({
-  emits: [\\"foo\\", \\"bar\\"] as unknown as undefined,
+  emits: [\\"foo\\", \\"bar\\"],
   setup(__props, { expose, emit }: { emit: ({ (e: 'foo' | 'bar'): void }), expose: any, slots: any, attrs: any }) {
   expose()
 
@@ -755,7 +755,7 @@ exports[`SFC compile <script setup> with TypeScript defineEmits w/ type (referen
 export type Emits = (e: 'foo' | 'bar') => void
       
 export default /*#__PURE__*/_defineComponent({
-  emits: [\\"foo\\", \\"bar\\"] as unknown as undefined,
+  emits: [\\"foo\\", \\"bar\\"],
   setup(__props, { expose, emit }: { emit: ((e: 'foo' | 'bar') => void), expose: any, slots: any, attrs: any }) {
   expose()
 
@@ -772,7 +772,7 @@ exports[`SFC compile <script setup> with TypeScript defineEmits w/ type (referen
 type Emits = (e: 'foo' | 'bar') => void
       
 export default /*#__PURE__*/_defineComponent({
-  emits: [\\"foo\\", \\"bar\\"] as unknown as undefined,
+  emits: [\\"foo\\", \\"bar\\"],
   setup(__props, { expose, emit }: { emit: ((e: 'foo' | 'bar') => void), expose: any, slots: any, attrs: any }) {
   expose()
 
@@ -789,7 +789,7 @@ exports[`SFC compile <script setup> with TypeScript defineEmits w/ type (type al
 type Emits = { (e: 'foo' | 'bar'): void }
       
 export default /*#__PURE__*/_defineComponent({
-  emits: [\\"foo\\", \\"bar\\"] as unknown as undefined,
+  emits: [\\"foo\\", \\"bar\\"],
   setup(__props, { expose, emit }: { emit: ({ (e: 'foo' | 'bar'): void }), expose: any, slots: any, attrs: any }) {
   expose()
 
@@ -805,7 +805,7 @@ exports[`SFC compile <script setup> with TypeScript defineEmits w/ type (type li
 "import { defineComponent as _defineComponent } from 'vue'
 
 export default /*#__PURE__*/_defineComponent({
-  emits: [\\"foo\\", \\"bar\\", \\"baz\\"] as unknown as undefined,
+  emits: [\\"foo\\", \\"bar\\", \\"baz\\"],
   setup(__props, { expose, emit }: { emit: ({(e: 'foo' | 'bar'): void; (e: 'baz', id: number): void;}), expose: any, slots: any, attrs: any }) {
   expose()
 
@@ -821,7 +821,7 @@ exports[`SFC compile <script setup> with TypeScript defineEmits w/ type 1`] = `
 "import { defineComponent as _defineComponent } from 'vue'
 
 export default /*#__PURE__*/_defineComponent({
-  emits: [\\"foo\\", \\"bar\\"] as unknown as undefined,
+  emits: [\\"foo\\", \\"bar\\"],
   setup(__props, { expose, emit }: { emit: ((e: 'foo' | 'bar') => void), expose: any, slots: any, attrs: any }) {
   expose()
 
@@ -840,8 +840,8 @@ export interface Props { x?: number }
 export default /*#__PURE__*/_defineComponent({
   props: {
     x: { type: Number, required: false }
-  } as unknown as undefined,
-  setup(__props: { x?: number }, { expose }) {
+  },
+  setup(__props: any, { expose }) {
   expose()
 
       
@@ -859,8 +859,8 @@ export type Props = { x?: number }
 export default /*#__PURE__*/_defineComponent({
   props: {
     x: { type: Number, required: false }
-  } as unknown as undefined,
-  setup(__props: { x?: number }, { expose }) {
+  },
+  setup(__props: any, { expose }) {
   expose()
 
       
@@ -878,8 +878,8 @@ interface Props { x?: number }
 export default /*#__PURE__*/_defineComponent({
   props: {
     x: { type: Number, required: false }
-  } as unknown as undefined,
-  setup(__props: { x?: number }, { expose }) {
+  },
+  setup(__props: any, { expose }) {
   expose()
 
       
@@ -923,34 +923,8 @@ export default /*#__PURE__*/_defineComponent({
     literalUnionMixed: { type: [String, Number, Boolean], required: true },
     intersection: { type: Object, required: true },
     foo: { type: [Function, null], required: true }
-  } as unknown as undefined,
-  setup(__props: {
-        string: string
-        number: number
-        boolean: boolean
-        object: object
-        objectLiteral: { a: number }
-        fn: (n: number) => void
-        functionRef: Function
-        objectRef: Object
-        array: string[]
-        arrayRef: Array<any>
-        tuple: [number, number]
-        set: Set<string>
-        literal: 'foo'
-        optional?: any
-        recordRef: Record<string, null>
-        interface: Test
-        alias: Alias
-        method(): void
-
-        union: string | number
-        literalUnion: 'foo' | 'bar'
-        literalUnionNumber: 1 | 2 | 3 | 4 | 5
-        literalUnionMixed: 'foo' | 1 | boolean
-        intersection: Test & {}
-        foo: ((item: any) => boolean) | null
-      }, { expose }) {
+  },
+  setup(__props: any, { expose }) {
   expose()
 
       
@@ -968,8 +942,8 @@ type Props = { x?: number }
 export default /*#__PURE__*/_defineComponent({
   props: {
     x: { type: Number, required: false }
-  } as unknown as undefined,
-  setup(__props: { x?: number }, { expose }) {
+  },
+  setup(__props: any, { expose }) {
   expose()
 
       
@@ -1039,15 +1013,15 @@ export default /*#__PURE__*/_defineComponent({
     foo: { type: String, required: false },
     bar: { type: Number, required: false },
     baz: { type: Boolean, required: true }
-  }, { ...defaults }) as unknown as undefined,
-  setup(__props: {
+  }, { ...defaults }),
+  setup(__props: any, { expose }) {
+  expose()
+
+const props = __props as {
         foo?: string
         bar?: number
         baz: boolean
-      }, { expose }) {
-  expose()
-
-const props = __props
+      }
       
       
 return { props, defaults }
@@ -1065,11 +1039,11 @@ export default /*#__PURE__*/_defineComponent({
     bar: { type: Number, required: false },
     baz: { type: Boolean, required: true },
     qux: { type: Function, required: false, default() { return 1 } }
-  } as unknown as undefined,
-  setup(__props: { foo: string, bar?: number, baz: boolean, qux(): number }, { expose }) {
+  },
+  setup(__props: any, { expose }) {
   expose()
 
-const props = __props
+const props = __props as { foo: string, bar?: number, baz: boolean, qux(): number }
       
       
 return { props }
index 8a8b591ce0977c2be39decc2f2f1a73ae8493abf..e5c2f4ae75213798feff36f55970388730feb978 100644 (file)
@@ -861,7 +861,7 @@ const emit = defineEmits(['a', 'b'])
       `)
       assertCode(content)
       expect(content).toMatch(`emit: ((e: 'foo' | 'bar') => void),`)
-      expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
+      expect(content).toMatch(`emits: ["foo", "bar"]`)
     })
 
     test('defineEmits w/ type (union)', () => {
@@ -884,9 +884,7 @@ const emit = defineEmits(['a', 'b'])
       `)
       assertCode(content)
       expect(content).toMatch(`emit: (${type}),`)
-      expect(content).toMatch(
-        `emits: ["foo", "bar", "baz"] as unknown as undefined`
-      )
+      expect(content).toMatch(`emits: ["foo", "bar", "baz"]`)
     })
 
     test('defineEmits w/ type (interface)', () => {
@@ -898,7 +896,7 @@ const emit = defineEmits(['a', 'b'])
       `)
       assertCode(content)
       expect(content).toMatch(`emit: ({ (e: 'foo' | 'bar'): void }),`)
-      expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
+      expect(content).toMatch(`emits: ["foo", "bar"]`)
     })
 
     test('defineEmits w/ type (exported interface)', () => {
@@ -910,7 +908,7 @@ const emit = defineEmits(['a', 'b'])
       `)
       assertCode(content)
       expect(content).toMatch(`emit: ({ (e: 'foo' | 'bar'): void }),`)
-      expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
+      expect(content).toMatch(`emits: ["foo", "bar"]`)
     })
 
     test('defineEmits w/ type (type alias)', () => {
@@ -922,7 +920,7 @@ const emit = defineEmits(['a', 'b'])
       `)
       assertCode(content)
       expect(content).toMatch(`emit: ({ (e: 'foo' | 'bar'): void }),`)
-      expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
+      expect(content).toMatch(`emits: ["foo", "bar"]`)
     })
 
     test('defineEmits w/ type (exported type alias)', () => {
@@ -934,7 +932,7 @@ const emit = defineEmits(['a', 'b'])
       `)
       assertCode(content)
       expect(content).toMatch(`emit: ({ (e: 'foo' | 'bar'): void }),`)
-      expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
+      expect(content).toMatch(`emits: ["foo", "bar"]`)
     })
 
     test('defineEmits w/ type (referenced function type)', () => {
@@ -946,7 +944,7 @@ const emit = defineEmits(['a', 'b'])
       `)
       assertCode(content)
       expect(content).toMatch(`emit: ((e: 'foo' | 'bar') => void),`)
-      expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
+      expect(content).toMatch(`emits: ["foo", "bar"]`)
     })
 
     test('defineEmits w/ type (referenced exported function type)', () => {
@@ -958,7 +956,7 @@ const emit = defineEmits(['a', 'b'])
       `)
       assertCode(content)
       expect(content).toMatch(`emit: ((e: 'foo' | 'bar') => void),`)
-      expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
+      expect(content).toMatch(`emits: ["foo", "bar"]`)
     })
 
     test('runtime Enum', () => {
index ac38540f60ef476151168cde093a1895232b5c26..13f597cc148f01d2a48cb8d55458315915aa32be 100644 (file)
@@ -592,7 +592,7 @@ export function compileScript(
       )})`
     }
 
-    return `\n  props: ${propsDecls} as unknown as undefined,`
+    return `\n  props: ${propsDecls},`
   }
 
   function genSetupPropsType(node: TSTypeLiteral | TSInterfaceBody) {
@@ -600,7 +600,7 @@ export function compileScript(
     if (checkStaticDefaults()) {
       // if withDefaults() is used, we need to remove the optional flags
       // on props that have default values
-      let res = `{ `
+      let res = `{ `
       const members = node.type === 'TSTypeLiteral' ? node.members : node.body
       for (const m of members) {
         if (
@@ -629,7 +629,7 @@ export function compileScript(
       }
       return (res.length ? res.slice(0, -2) : res) + ` }`
     } else {
-      return `: ${scriptSetupSource.slice(node.start!, node.end!)}`
+      return scriptSetupSource.slice(node.start!, node.end!)
     }
   }
 
@@ -1051,17 +1051,25 @@ export function compileScript(
   // 9. finalize setup() argument signature
   let args = `__props`
   if (propsTypeDecl) {
-    args += genSetupPropsType(propsTypeDecl)
+    // mark as any and only cast on assignment
+    // since the user defined complex types may be incompatible with the
+    // inferred type from generated runtime declarations
+    args += `: any`
   }
   // inject user assignment of props
   // we use a default __props so that template expressions referencing props
   // can use it directly
   if (propsIdentifier) {
-    s.prependRight(startOffset, `\nconst ${propsIdentifier} = __props`)
+    s.prependRight(
+      startOffset,
+      `\nconst ${propsIdentifier} = __props${
+        propsTypeDecl ? ` as ${genSetupPropsType(propsTypeDecl)}` : ``
+      }`
+    )
   }
   // inject temp variables for async context preservation
   if (hasAwait) {
-    const any = isTS ? `:any` : ``
+    const any = isTS ? `: any` : ``
     s.prependRight(startOffset, `\nlet __temp${any}, __restore${any}\n`)
   }
 
@@ -1589,7 +1597,7 @@ function genRuntimeEmits(emits: Set<string>) {
   return emits.size
     ? `\n  emits: [${Array.from(emits)
         .map(p => JSON.stringify(p))
-        .join(', ')}] as unknown as undefined,`
+        .join(', ')}],`
     : ``
 }