Skip to content

satisfies removes the readonly constraint from a tupleΒ #64274

Closed

Description

@Sector6759

πŸ”Ž Search Terms

satisfies tuple readonly

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about the satisfies operator.

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=6.0.0-dev.20260416#code/C4TwDgpgBAKlC8UBEBBJUA+yBCSDcAUAQMYD2AdgM7BTACuYANtIgNqpIA0OSAulAENKUMlWCESFarQbMAygOABLSgDMlEYWw7ckufkJFSalRSvWbYrXnigB6O1AAG9JhAXK1Gyk6gqopKq04NBO7Gi6+r4ARnQ0AJJQEAAekMTAEAAmzgBOEAKZFIwgUOFcPLxORKLSeWQ52YgA3lAoAFzIqqSk5dgdSNECOegAvoLCNeLVxlB1pA0e5t4IUC3tnd29-YPDUGOGk1CmnhbCAEoQ9ZkAPDDc1DlK5ADmAHy2DrmX85mLXpq+AAWhmAgOgpgAttBQJBxl8rk5uAB3QFKYiAvzCJwtPIFIoldZILo9Wy4wrkYpQPrIHb4PZVIA

πŸ’» Code

type T = "A" | "B";

const tuple = ["A", "B"] as const;

const tupleSatisfies = ["A", "B"] as const satisfies T[]; // `tupleSatisfies` is of type `["A", "B"]` but I expected `readonly ["A", "B"]`

const record = { A: "foo", B: "bar" } as const;

const recordSatisfies = { A: "foo", B: "bar" } as const satisfies Record<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.

I am aware that I can do the following:

const tupleSatisfies = ["A", "B"] as const satisfies readonly T[];

But the again I also didn't have to use

const recordSatisfies = { A: "foo", B: "bar" } as const satisfies Readonly<Record<T, string>>;

Activity

  1. jcalz commented on Sep 15, 2026

    @jcalz
    Contributor

    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.

  2. Sector6759 commented on Sep 15, 2026

    @Sector6759
    Author

    Thanks a lot for the explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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