-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Open
Description
[docs] Clarify typing with computed<T>
vs return annotation (excess property checks)
Summary
The docs recommend typing a computed value with a generic:
const double = computed<number>(() => {
return count.value * 2
})
This works, but there is a subtle TypeScript behavior that can surprise users:
- With
computed<Foo>(...)
, TypeScript only checks that the return value is assignable toFoo
. - Extra properties not present in
Foo
are silently allowed because excess property checks do not apply when inferring into a generic. - Using a function return type annotation
(): Foo => ...
does enforce excess property checks and will reject extra properties.
Minimal reproduction
import { computed } from 'vue'
interface FooBarInterface {
foo: boolean
}
// 1) Generic parameter (loose): allows extra props
const first = computed<FooBarInterface>(() => ({
foo: false,
bar: 'test', // ✅ no error (extra property allowed)
}))
// 2) Return annotation (strict): rejects extra props
const second = computed(
(): FooBarInterface => ({
foo: false,
bar: 'test', // ❌ TS2353: Object literal may only specify known properties
}),
)
Strict alternative with satisfies
To keep the concise generic style while getting strictness, suggest the satisfies
operator:
const third = computed(() => ({
foo: false,
bar: 'test', // ❌ error: 'bar' is not in FooBarInterface
} satisfies FooBarInterface))
This enforces that the object conforms exactly to FooBarInterface
without allowing extra properties.
Why this happens (TypeScript behavior)
This is not a Vue/runtime issue but a well-known TypeScript typing nuance:
- Generics (
computed<Foo>(...)
) behave like a constraint: the inferred return just needs to be assignable toFoo
. Excess property checks do not run for values inferred into a generic parameter. - Explicit return annotations (
(): Foo => ...
) do trigger excess property checks on object literals, so extra fields are rejected.
Because computed
is a generic helper, this difference is unavoidable at the type-system level.
Proposed docs improvement
In the “Typing computed()
” section, add a short note warning about this difference and showing the stricter alternatives.
Environment
- Vue: 3.5.18
- TypeScript: 5.9.2
- Nuxt: 4.0.3
This request is strictly about improving documentation and developer ergonomics.
martinhellocse, rosmis-cse and godartm
Metadata
Metadata
Assignees
Labels
No labels