microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
99.75k stars 12.34k forks source link

Suggestion: treat readonly static members of class as namespace members #38803

Open shrinktofit opened 4 years ago

shrinktofit commented 4 years ago

Search Terms

static member; namespace; type

Maybe related issues: https://github.com/microsoft/TypeScript/issues/38207

Suggestion

Readonly static members of class should act like namespace members. Especially, when that member is assigned as an alias of enumeration or other class.

Use Cases

With the suggestion,

enum Color { red, }
class Image {
    public static readonly Color = Color; // Marked as readonly, so tsc can ensure it's an alias
}

The Image.Color should be an alias of enumeration Color. So we can use it when an enumeration may be used:

console.log(Image.Color.red); // OK
function f(color: Image.Color) { // OK: used as type #1
    if (color === Image.Color.red){ /* ... */ }
}

#1 is invalid for now because tsc does not treat Image.Color as a type. To use Image.Color as a type, we may supply a verbose declaration according to the declaration merging rule of TypeScript:

namespace Image {
    export type Color = (typeof Color)[keyof typeof Color]; // :(
}

It's verbose...

Examples

Sometimes we want to embed enumerations, classes into other classes. Because we don't want directly expose that enumueration/class into module scope.

Checklist

My suggestion meets these guidelines:

kraenhansen commented 1 year ago

@RyanCavanaugh you've marked this as "Awaiting More Feedback". I'm curious what sort of feedback you're looking for?

Personally I've encountered this a couple of times and was now about to create an issue for it .. then I found this.

There's a couple of reasons I think it would be valuable to provide this as an alternative for the only know workaround:

All in all, I think this is an example of something that would provide great value at what I would expect to be little cost.

RyanCavanaugh commented 1 year ago

FWIW it would not be little cost; quite the opposite because this would change how binding occurs at a fundamental level (since classes currently don't create a namespace meaning).

Regarding feedback, generally we're looking for both volume and severity, meaning that ideally lots of people are effectively blocked by some lack of feature. 1 heart and 1 comment in 2 years, when it's clearly a "nice to have" = this is extremely unlikely to happen.

kraenhansen commented 1 year ago

For more context, we're reimplementing a package that was heavily relying on namespaces. We want to avoid breaking the API and this is the sort of code we see ourselves writing in the process (note the unfortunate duplication of type names and template arguments). It would be much simpler to just declare these as static (read-only) members on the class.