vuejs / language-tools

⚡ High-performance Vue language tooling based-on Volar.js
https://marketplace.visualstudio.com/items?itemName=Vue.volar
MIT License
5.62k stars 377 forks source link

props on `template` are not checked #4539

Open brc-dd opened 1 week ago

brc-dd commented 1 week ago

Vue - Official extension or vue-tsc version

2.0.26

VSCode version

1.92.0-insider

Vue version

3.4.31

TypeScript version

5.5.3

System Info

No response

Steps to reproduce

  1. git clone git@github.com:brc-dd/volar-template-key-bug.git
  2. pnpm i
  3. pnpm vue-tsc --noEmit

Pasting here for completeness:

<script setup lang="ts"></script>

<template>
  <template v-if="true" :key=""></template>
  <template v-if="true" :key="{}"></template>

  <div v-if="true" :key=""></div>
  <div v-if="true" :key="{}"></div>
</template>

What is expected?

Error on line 4, 5, 7, 8 of Foo.vue

What is actually happening?

Error is only on line 7, 8.

There should be an error on line 4 saying v-bind is missing expression.

There should be an error on line 5 saying Type '{}' is not assignable to type 'PropertyKey | undefined'.

Link to minimal reproduction

https://github.com/brc-dd/volar-template-key-bug

Any additional comments?

Is it possible to show vue errors when running vue-tsc? They are currently shown only in the editor. (Line 7 in the above example.)

davidmatter commented 1 week ago

Input

<script setup lang="ts"></script>

<template>
  <template v-if="true" :key="">
    <div></div>
  </template>
  <template v-if="true" :key="{}">
    <div></div>
  </template>

  <div v-if="true" :key=""></div>
  <div v-if="true" :key="{}"></div>
</template>

Output

// ...
if (true) {
__VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({});
}
if (true) {
__VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({});
}
if (true) {
__VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({key: ((__VLS_ctx.)), });
// @ts-ignore
[,];
}
if (true) {
__VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({key: (({})), });
}
// ...

Should?

// ...
if (true) {
- __VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({});
+ __VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({key: ((undefined))});
}
if (true) {
- __VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({});
+ __VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({key: (({}))});
}
if (true) {
- __VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({key: ((__VLS_ctx.)), });
+ __VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({key: ((undefined))});
// @ts-ignore
[,];
}
if (true) {
__VLS_elementAsFunction(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({key: (({})), });
}
// ...
so1ve commented 1 week ago

https://github.com/vuejs/core/blob/93324b2ec06b26662b77abc2a75d21ecbe8913db/packages/compiler-core/src/transforms/vIf.ts#L206-L216

A <template> with v-if will be turned into an IF_BRANCH node, we should handle it in https://github.com/vuejs/language-tools/blob/master/packages/language-core/lib/codegen/template/elementDirectives.ts.

brc-dd commented 1 week ago

Ah, it's not working for v-for in template's either. I had put v-if for easier repro. v-for + key is more common usage.

so1ve commented 1 week ago

Should be fixed by https://github.com/vuejs/language-tools/commit/cb540323d4f0e80feed4feb4fea301f7d532f0c5? Do you mean there is no type checking?

brc-dd commented 1 week ago

Do you mean there is no type checking?

Yeah it's not there for key. This should've shown error in line 3:

<script setup lang="ts"></script>

<template>
  <template v-for="x in [1]" :key="{}">
    <div>{{ x }}</div>
  </template>
</template>
so1ve commented 6 days ago

Got it :open_hands:

so1ve commented 6 days ago

My PR doesn't report v-bind is missing expression, since CompilerDOM.compile() itself doesn't throw on those invalid directives.

brc-dd commented 6 days ago

Ah yeah. It can be left I guess. I'll track it on the core repo. Looks like compiler-dom is generating invalid JS for <template v-for="x in [1]" :key="" /> without complaining.

so1ve commented 6 days ago

Yeah, v-if with :key generates { key: 0 } while v-for with :key generates { key: }