Description
Vue version
3.4.31
Link to minimal reproduction
Steps to reproduce
Define a computed property with an explicit generic, and a return value that does not match the type of the generic. Additionally, define a computed property that may return null. Like so:
<script setup lang="ts">
import { computed } from 'vue'
type UserDTO = {
id: string
name: string
}
const notNullUser = computed<UserDTO>(() => {
return null // Problem #1: the generic of the computed method is defined as `UserDTO`, that type does NOT include `null`, therefore, this should not compile
})
// Setup for Problem #2
const maybeNullUser = computed<UserDTO | null>(() => {
return null
})
</script>
Then, use the computed properties in your template, as such:
<template>
<p>Name: {{ notNullUser.id }}</p> <!-- Problem #1: this is technically expected, as `computed` type is `UserDTO` and cannot be null, however, for some reason the compiler does not detect the method ACTUALLY returning `null`, and as a result we get this error at runtime -->
<p>Name 2: {{ maybeNullUser.name }}</p> <!-- Problem #2: `maybeNullUser` is typed as `UserDTO | null`, therefore, this property access should not compile as `maybeNullUser` can be null (and, in this example, is) -->
</template>
What is expected?
I expect to receive two compile-time errors:
- The first
computed
call should fail compilation, telling us thatnull
is not assignable to theUserDTO
type passed as a generic to the computed method. - The access of
maybeNullUser.name
in the secondp
tag should should result in an error saying something along the lines ofuser is potentially null
, and demanding that access tomaybeNullUser.name
be locked behind av-if="maybeNullUser"
check before being accessed (i.e., the most basic type narrowing)
What is actually happening?
The component compiled without failure, and rendering the component results in an error at runtime: Cannot read properties of null (reading 'id')
. This is caused by the access of notNullUser.id
in the p
tag in the reproduction.
I also presume that the same error would happen as a result of accessing the second p
tag, the maybeNullUser.name
accessor should fail, as maybeNullUser
's type dictates that it can be null.
This behavior occurs regardless of SSR, but I have enabled SSR in the reproduction link because that is what I use in my projects. That being said, I do not believe that this is an issue with SSR itself.
System Info
I made this reproduction on the Vue SFC playground, and shared a link. As a result, I am not sure how relevant the result of npx envinfo
is, when ran in an unrelated environment.
Any additional comments?
I noticed that type narrowing of discriminated unions does not work within templates. I decided to investigate further, and found that this reproduction is a lot less complex, and fails in a similar way. This leads me to believe that there is an overall lack of support for type information within the template, despite Vue documentation saying TypeScript is indeed supported within templates.