TypeScript
TypeScript copied to clipboard
Design Meeting Notes, 10/1/2024
The internal Modifier
https://github.com/microsoft/TypeScript/issues/5228
- We've discussed an
internalmodifier on-and-off since 2015. - High 👍 count, but haven't pursued it.
- Today you can use
/** @internal */JSDoc comments to mark things as internal, and--stripInternal. - Previously,
--stripInternalwas not even publicly documented. - Also, have to do hacks to make
.d.tsbundling work with this. - Would be nice to have something more formal.
- Also,
internalallows you to know whether something is getting overridden in a subtype.
- Also,
- Idea:
-
internalstays in.d.tsoutput. - Project package or project boundary.
- Only operates in the same compilation.
- Not allowed to
importanexport internal. - At the
tsconfig.jsonlevel, internal access might be granted and asserted in a few ways:-
Maybe an option for specific packages
{ "compilerOptions": { // Grant access to 'consuming-package': "internalsVisibleTo": ["consuming-package"], // Assert access to 'dependency-package': "internalsVisibleFrom": ["dependency-package"], } } -
Possibly just something on each reference
{ "references": [ { "path": "../package", "allowInternals": true } ] }
-
-
- What are the rules?
- Can't mix (e.g. no
publicandinternalin the same declaration).
- Can't mix (e.g. no
- Why not JSDoc?
- Relatively expensive for this.
- What should tools do with
internal?- Should bundlers limit access to an
internalmember that'sexport *'d?- We'd sort of hope "no".
- Does the declaration emitter have to worry about this now?
- What happens when you run
keyofon a type withinternal?- Probably should do the same thing that
privatedoes. - But does that mean that
keyofmeans something different depending on where it's written.
- Probably should do the same thing that
- How does this work for overload resolution?
- Do overloads get skipped?
- Do they get related appropriately?
- Should bundlers limit access to an
- The "someone subclassed this" issue is not something we've heard a ton of.
- Do most people use
.d.tsbundlers that can do this post-processing?- No, mostly not.
- Some of our build tooling would be simpler if we had this.
- But doesn't it mean that we're just making other stuff more complex?
- For example,
publicandprivateoverloads can't be mixed today. - Well maybe we do need to explore that restriction.
- For example,
- Also, some of the point of
--stripInternalis to not make things publicly known and avoid documenting functions to prevent usage. - Back to this question again - what do you do when you have a mapped type?
-
internalis inaccessible depending on where it's used. -
privateandprotectedhas this, but it's not witnessable in the majority of code (which is outside of the class).
-
- Coming back to
keyof- is this now a location-sensitive operation?- The idea that you will get different types based on instantiation location is not something we've done before.
- Really don't like that.
- The idea that you will get different types based on instantiation location is not something we've done before.
- What do you want?
- Scope visibility to peers.
- Keep existence undocumented.
- Do we really want an ergonomic way for people to import something marked
internal?- We don't have to do everything listed above.
- Can do this just on the module level.
- Maybe even just that and the property level.
- "Good enough" as
readonly.
- Cautious but curious around a solution.
- Not convinced that we would have a solution that we'd entirely be happy with.
- Must preserve existing invariants around how type information appears.
- One opinion: sympathetic to a
package-like modifier, but doesn't entirely solve the problem for our own usage for hiding entities in the resulting declaration file.