question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Valid typescript when using defineEmits() results in bad code transformation during compile

See original GitHub issue

Version

3.2.30

Reproduction link

sfc.vuejs.org/

Steps to reproduce

In a <script setup lang="ts"> block, this causes an error during compilation:

<script setup lang="ts">
import { defineEmits } from 'vue'

interface Emits {
  (e: 'foo'): void
}
 
const emit: Emits = defineEmits(['foo'])
</script>

From vite:

  Expected "}" but found ":"
  9  |  const _sfc_main = /*#__PURE__*/_defineComponent({
  10 |    emits: ['foo'],
  11 |    setup(__props, { expose, emit: emit: Emits }) {
     |                                       ^
  12 |    expose();
  13 |  
  
      at failureErrorWithLog (C:\Work\scolasta2\node_modules\.pnpm\esbuild@0.13.15\node_modules\esbuild\lib\main.js:1493:15)
      at C:\Work\scolasta2\node_modules\.pnpm\esbuild@0.13.15\node_modules\esbuild\lib\main.js:1282:29
      at C:\Work\scolasta2\node_modules\.pnpm\esbuild@0.13.15\node_modules\esbuild\lib\main.js:629:9
      at handleIncomingPacket (C:\Work\scolasta2\node_modules\.pnpm\esbuild@0.13.15\node_modules\esbuild\lib\main.js:726:9)
      at Socket.readFromStdout (C:\Work\scolasta2\node_modules\.pnpm\esbuild@0.13.15\node_modules\esbuild\lib\main.js:596:7)
      at Socket.emit (node:events:390:28)
      at addChunk (node:internal/streams/readable:315:12)
      at readableAddChunk (node:internal/streams/readable:289:9)
      at Socket.Readable.push (node:internal/streams/readable:228:10)
      at Pipe.onStreamRead (node:internal/stream_base_commons:199:23)

What is expected?

It should compile

What is actually happening?

Doesn’t compile


This looks like a transformation error in the vue compiler, since the following works fine as a workaround:

const emit = defineEmits(['foo']) as Emits

But the above code is valid typescript and shouldn’t result in what is being generated.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
edison1105commented, Feb 10, 2022

you should use type declaration

const emit = defineEmits<Emits>()
0reactions
nborkocommented, Feb 21, 2022

As a quick explanation of my setup, I have a subdirectory for each component with the following structure:

// types.ts

// heavily documented with tsdoc
interface MyComponentProps {
    ...
}

// heavily documented with tsdoc
interface MyComponentEmits {
    ...
}

// synthetic type for api-extractor
// tsdoc style documentation for the actual component
interface MyComponent {
    props: MyComponentProps
    emits: MyComponentEmits
}
<comment><!-- MyComponent.vue --></comment>

<script setup lang="ts">
import { MyComponentEmits, MyComponentProps } from './types'

const props: MyComponentProps = defineProps({
    ...
})

// This is broken
const emit: MyComponentEmits = defineEmits([ ... ])

// some functionality
</script>
// index.ts

export { default as MyComponent } from './MyComponent.vue'

This helps keep the documentation and types separated from the SFC to keep the code clean and easier to maintain, and I point api-extractor to a top level types.ts that imports and re-exports the types from each of the components, for further processing into API documentation.

EDIT: Updated the sample synthetic interface for clarity

Read more comments on GitHub >

github_iconTop Results From Across the Web

Problems with Vue 3.2 <script setup> tag and TypeScript types
I have a simple use case where I want to display a user ID in the template. My code is technically working. It...
Read more >
Take control of unexpected data at runtime with TypeScript
Using TypeScript to stop unexpected data from breaking your app ... a familiar value in a wrong way in the code, you'll get...
Read more >
How to use the script setup syntax in Vue 3 | Ninja Squad
How to use the `script setup` syntax in Vue 3 ... import it in your code: Vue automatically understands it when it compiles...
Read more >
The common misconception about TypeScript
During compilation, TypeScript compiler checks for type-mismatches and report such errors. For example, a number can be added to only another ...
Read more >
TypeScript with Composition API - Vue.js
When using <script setup> , the defineProps() macro supports inferring the props types based on its argument: vue <script setup lang="ts"> const props ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found