Subscribe on changes!

Accessing generically typed props in <script lang='ts' setup> causes transform failure

avatar
Oct 1st 2022

Vue version

3.2.38

Link to minimal reproduction

sfc playground

Steps to reproduce

I am trying to create a reusable Vue 3 component with generically typed props. Let's say I want a props interface that looks something like:

// ChildComponent.vue
interface MyProps<T> {
  propOne: T
  propTwo: () => Array<T>
}

The goal of this is so that something like the below would fail:

// ParentComponent.vue
<template>
  <!-- 5 is a number, but "foo" and "bar" are strings 👎  -->
  <child-component
    :prop-one="5"
    :prop-two="() => ["foo", "bar"]"
  />
</template

Using this example, and also running into this issue I came up with the following:

// ChildComponent.vue
<script setup lang="ts">
defineProps<MyChildProps<unknown>>()
</script>

<script lang="ts">
export interface MyChildProps<T> {
  propOne: T
  propTwo: () => Array<T>
}
</script>

<template>
  <div>{{ propOne }}</div>
</template>
// ChildComponentWithGenerics.vue
<script lang="ts">
import ChildComponent from './ChildComponent.vue'
import type { MyChildProps } from './ChildComponent.vue'

type ChildComponentWithGenerics = new <T>(props: MyChildProps<T>) => {
  $props: MyChildProps<T>
}

export default ChildComponent as ChildComponentWithGenerics
</script>

This successfully results in the following:

// ParentComponent.vue
<script setup lang="ts">
const getSomeStrings = () => ["foo", "bar"]
</script>

<template>
  <!-- 5 is a number, but "foo" and "bar" are strings 👎  -->
  <child-component
    :prop-one="5"
    :prop-two="getSomeStrings"
  />

  <!-- this is fine! 👍  -->
  <child-component
    prop-one="vite rocks!"
    :prop-two="getSomeStrings"
  />
</template>

Great, all working fine. That is, until I try and access the props in ChildComponent.vue... As soon as I add const props = to then do some logic with the props, I get an error.

// ChildComponent.vue
<script setup lang="ts">

// accessing the props here causes the error ❌
const props = defineProps<MyChildProps<unknown>>()
</script>

<script lang="ts">
export interface MyChildProps<T> {
  propOne: T
  propTwo: () => Array<T>
}
</script>

<template>
  <div>{{ propOne }}</div>
</template>

I also created a repo more like my use case here

What is expected?

Have access to the component's props

What is actually happening?

An error is thrown:

[plugin:vite:vue] Transform failed with 1 error: /Users/josephmaylor/Desktop/vite-project/src/components/ChildComponent.vue:18:41: ERROR: Unexpected ")"

/Users/josephmaylor/Desktop/vite-project/src/components/ChildComponent.vue:18:41

Unexpected ")" 16 | expose(); 17 |
18 | const props = __props as Props>() | ^ 19 |
20 |

at failureErrorWithLog (/Users/josephmaylor/Desktop/vite-project/node_modules/.pnpm/esbuild@0.15.10/node_modules/esbuild/lib/main.js:1566:15) at /Users/josephmaylor/Desktop/vite-project/node_modules/.pnpm/esbuild@0.15.10/node_modules/esbuild/lib/main.js:805:29 at responseCallbacks. (/Users/josephmaylor/Desktop/vite-project/node_modules/.pnpm/esbuild@0.15.10/node_modules/esbuild/lib/main.js:671:9) at handleIncomingPacket (/Users/josephmaylor/Desktop/vite-project/node_modules/.pnpm/esbuild@0.15.10/node_modules/esbuild/lib/main.js:726:9) at Socket.readFromStdout (/Users/josephmaylor/Desktop/vite-project/node_modules/.pnpm/esbuild@0.15.10/node_modules/esbuild/lib/main.js:647:7) at Socket.emit (node:events:526: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:190:23

System Info

System:
    OS: macOS 12.6
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 21.29 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.14.2 - /usr/local/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 8.5.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 106.0.5249.91
    Firefox: 105.0.1
    Safari: 16.0
  npmPackages:
    vue: ^3.2.38 => 3.2.40

Any additional comments?

Original ticket in vite repo

avatar
Oct 2nd 2022

duplicate #5830