Ask
25
@two_privates ·

TypeScript has two kinds of private and they fail differently: when each one bites

The keyword and the hash are not two spellings of the same idea, and choosing by taste causes trouble later.

The keyword is compile-time only. It disappears entirely when compiled. At runtime the property is an ordinary one, visible to anything holding the object, enumerable, and reachable from plain JavaScript or a bracket lookup. It is a rule the compiler enforces on you, not a property of the object.

The hash is a real runtime private field. It is enforced by the engine, invisible to code outside the class, and not reachable at all from outside.

What that means in practice

  • Testing. A keyword private can be reached from a test with a cast. A hash field cannot, ever, so you have to test through the public surface. Some people consider that a feature.
  • Serialisation. Keyword privates appear in output when you convert an object to JSON, which surprises people and occasionally leaks something. Hash fields do not.
  • Structural typing. A class with a keyword private stops being structurally compatible with an identical class, which is sometimes exactly what you want and sometimes the reason a type stops matching for no visible reason.
  • Copying and proxies. Object spread drops hash fields, and proxies need care, because the field is tied to the actual instance.
  • Library boundaries. If consumers might be plain JavaScript, only the hash actually protects anything.

Reasonable default: hash for genuine invariants and anything that must not be serialised or reached. Keyword for internals where the goal is communicating intent within a codebase you control.

8 answers Share
Report

Answering anonymously, a moderator will review it first.

  • @library_author · 2w ago

    From the library side the choice is not taste at all: the hash gives you a genuine guarantee you can rely on when someone else's code holds your object, and the keyword gives you a note in the documentation. If your class is part of a public API and the invariant matters, that difference is the whole decision.

    17
    Share
    Reply

    Answering anonymously, a moderator will review it first.

    Report
  • @just_use_hash · 3w ago · 3 replies

    Picked hash everywhere and stopped thinking about it. The two costs are real and small: your tests go through the public surface, and spreading an object loses the fields.

    The first turned out to be an improvement. The tests that could reach into internals were the ones that broke on every refactor, and losing that ability made them less brittle. Not sure I would have chosen it for that reason, but that is what happened.

    16
    Share
    Reply

    Answering anonymously, a moderator will review it first.

    Report
    • @decorators_broke · 2w ago · 2 replies

      The hash bit me in a way worth knowing: anything that serialises by walking properties will not see them. Structured clone, a naive JSON round trip, and several validation libraries all quietly drop them, and you get an object that looks right and has lost half its state.

      The keyword version survives all of that, because at runtime it is an ordinary property.

      22
      Share
      Reply

      Answering anonymously, a moderator will review it first.

      Report
      • @just_use_hash · 2w ago

        Fair, and it is the strongest argument against hash-everywhere. Anything crossing a serialisation boundary wants the keyword.

        14
        Share
        Reply

        Answering anonymously, a moderator will review it first.

        Report
  • @runtime_vs_compile · 3w ago

    The clean way to remember it: one is a rule for the author, the other is a property of the object. Everything else follows.

    The failure I see most is a keyword private on a token or credential, then the object gets logged or serialised somewhere and it comes straight out. It was never hidden; it was only inconvenient to reach on purpose.

    23
    Share
    Reply

    Answering anonymously, a moderator will review it first.

    Report
  • @library_author · 3w ago

    A rule for the author versus a property of the object. Best one-line version of this I have read.

    7
    Share
    Reply

    Answering anonymously, a moderator will review it first.

    Report
  • @two_privates · 3w ago · 2 replies

    The structural typing one is the surprise. Two classes with identical shapes stop being interchangeable the moment one has a keyword private, and the error message does not obviously say why.

    1
    Share
    Reply

    Answering anonymously, a moderator will review it first.

    Report
    • @decorators_broke · 3w ago

      Structural typing stopping two identical shapes being interchangeable is the surprise that catches people in tests first.

      10
      Share
      Reply

      Answering anonymously, a moderator will review it first.

      Report