-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Inconsistent excess property checking with $state #17947
Description
Describe the problem
Hi Svelte team,
I ran into a small but noticeable difference in TypeScript behavior when using $state that caught me off guard during a refactor.
In our codebase, we renamed an optional property (e.g. from optional to optionalRenamed in the type). I expected TypeScript to flag any leftover usages of the old name — which it does in normal object literals and in some $state patterns, but not in others.
Here's a minimal example:
type Company = {
required: string;
optionalRenamed?: string;
};
const company1: Company = $state({
required: "",
optional: "" // No TS error — old property is silently accepted
});
const company2: Company = {
required: "",
optional: "" // TS errors (good): 'optional' does not exist in type 'Company'.ts(2353)
};
const company3 = $state<Company>({
required: "",
optional: "" // TS errors (good): 'optional' does not exist in type 'Company'.ts(2353)
});In the company1 case TypeScript doesn't catch the extra / obsolete property. Only when using the explicit generic ($state<Company>(…)), or when assigning a plain literal, do I get the helpful excess property error.
This made the rename refactor less safe than I expected since old prop names can linger without warnings.
I understand this is probably just how TypeScript handles fresh object literals vs inferred generics, but from a Svelte user's perspective it creates an inconsistency between two very similar-looking patterns.
Is this difference considered expected / by design? Or is there interest in making the behavior more consistent (e.g. so the inline $state({ … }) pattern also triggers the stricter check when assigned to a typed variable)?
Thanks for any insight and your amazing work with svelte!
Describe the proposed solution
- add a note in the $state type docs
explicitly warning about this difference and recommending the generic form when strictness is desired. - improve $state or make the generic form $state the strongly encouraged default
- ?
Importance
would make my life easier