Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Suggestion: Clarify typing with computed<T> vs return annotation (excess property checks) #3286

Open
@CesarWatrin

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 to Foo.
  • 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 to Foo. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

        AltStyle によって変換されたページ (->オリジナル) /