You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
satisfies removes the readonly constraint from a tupleΒ #64274
typeT="A"|"B";consttuple=["A","B"]asconst;consttupleSatisfies=["A","B"]asconstsatisfiesT[];// `tupleSatisfies` is of type `["A", "B"]` but I expected `readonly ["A", "B"]`constrecord={A: "foo",B: "bar"}asconst;constrecordSatisfies={A: "foo",B: "bar"}asconstsatisfiesRecord<T,string>;// `recordSatisfies` has the same type as `record`, which is `{ readonly A: "foo"; readonly B: "bar"; }`
π Actual behavior
The satisfies operator removes the readonly constraint from the tuple elements.
π Expected behavior
The type of the resulting value should be same as if satisfies wasn't used at all.
Additional information about the issue
I've read through some existing issues explaining how satisfies has an impact on the contextual type, but I still don't understand why it would remove the readonly constraint from array/tuple elements which are simply properties of an array object, whereas satisfies does not remove the readonly constraint from an as const non-array object.
This is working as intended, as implemented in #55229. It's not specifically about satisfies, but about as const, and as such this is effectively a duplicate of #57107.
Do note there is an important difference between using readonly on array/tuple types and using it on non-array object types. See Improvements for ReadonlyArray and readonly tuples. It's not just that individual properties/elements are readonly. A readonly array type lacks mutating methods like push(). So while {readonly A: "foo", readonly B: "bar"} extends {A: "foo", B: "bar"} and vice versa, readonly ["A", "B"] does not extend ["A", "B"]. Therefore satisfies T[] is a stronger constraint than satisfies readonly T[].
Per #55229, as const will result in mutable array types when used in a context that expects such types. As mentioned, it isn't specifically about satisfies. The same thing happens with const x: string[] = ["a"] as const. That used to fail because ["a"] as const would unconditionally result in the type readonly ["a"] which does not satisfy string[]. Now it succeeds because the type of ["a"] as const depends on context and since string[] is expected, you get type ["a"] instead.
Before #55229, ["A", "B"] as const satisfies T[] would just fail whereas { A: "foo", B: "bar" } as const satisfies Record<T, string> would succeed. Now they both succeed and you get what you asked for.
Activity
jcalz commentedon Sep 15, 2026
This is working as intended, as implemented in #55229. It's not specifically about
satisfies, but aboutas const, and as such this is effectively a duplicate of #57107.Do note there is an important difference between using
readonlyon array/tuple types and using it on non-array object types. See Improvements forReadonlyArrayandreadonlytuples. It's not just that individual properties/elements are readonly. A readonly array type lacks mutating methods likepush(). So while{readonly A: "foo", readonly B: "bar"}extends{A: "foo", B: "bar"}and vice versa,readonly ["A", "B"]does not extend["A", "B"]. Thereforesatisfies T[]is a stronger constraint thansatisfies readonly T[].Per #55229,
as constwill result in mutable array types when used in a context that expects such types. As mentioned, it isn't specifically aboutsatisfies. The same thing happens withconst x: string[] = ["a"] as const. That used to fail because["a"] as constwould unconditionally result in the typereadonly ["a"]which does not satisfystring[]. Now it succeeds because the type of["a"] as constdepends on context and sincestring[]is expected, you get type["a"]instead.Before #55229,
["A", "B"] as const satisfies T[]would just fail whereas{ A: "foo", B: "bar" } as const satisfies Record<T, string>would succeed. Now they both succeed and you get what you asked for.Sector6759 commentedon Sep 15, 2026
Thanks a lot for the explanation.