Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Generic Class + Namespace Intellisense #60943

Open
6 tasks done
LukeAbby opened this issue Jan 9, 2025 · 3 comments
Open
6 tasks done

Improve Generic Class + Namespace Intellisense #60943

LukeAbby opened this issue Jan 9, 2025 · 3 comments
Labels
Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Milestone

Comments

@LukeAbby
Copy link

LukeAbby commented Jan 9, 2025

πŸ” Search Terms

generic class, namespace, intellisense, hover hint

βœ… Viability Checklist

⭐ Suggestion

The hoverhint on namespaces declaration merged with generic classes gets ugly. I would prefer if they were simpler. Here's an example:

Image

Because namespaces cannot access the generics of the class I also think it's a bit misleading of a display and arguably a bug. If it is intentional I would love to know. However I opened this issue as a feature request partially because I would like it to change even if this behavior is intentional.

This same phenomenon does not happen with associated functions only with classes. Perhaps this is because namespaces can be automatically generated on functions:

function identity<T extends number>(t: T): T { return x }

identity.prop = 123;

Compiles to this .d.ts file:

declare function identity<T extends number>(t: T): T;
declare namespace identity {
    var prop: number;
}

However I cannot find a way to get a poor intellisense even when I manually add types, consts etc. so it appears to be a phenomenon exclusive to classes.

πŸ“ƒ Motivating Example

declare namespace ClassAndNamespace {
    type Example = 1 | 2 | 3;
    //   ^ Is currently: type ClassAndNamespace<T extends ClassAndNamespace.Example>.Example = 1 | 2 | 3
    //     want: `type ClassAndNamespace.Example = 1 | 2 | 3`

   const example: 123;
   //    ^ Is currently: `const ClassAndNamespace<T extends ClassAndNamespace.Example>.example: 123`
   //      want: `const ClassAndNamespace.example: 123`
}

declare class ClassAndNamespace<T extends ClassAndNamespace.Example> {}
//                                                          ^ Same display as in namespace.

ClassAndNamespace.example;
//                ^ Same display as in namespace.

declare class Subclass<T extends ClassAndNamespace.Example> extends ClassAndNamespace<T> {}
//                                                 ^ Same display as in namespace.

const instance = new Subclass();
//                   ^ Is currently: constructor Subclass<ClassAndNamespace<T extends ClassAndNamespace.Example>.Example>(): Subclass<ClassAndNamespace.Example>
//                     want: constructor Subclass<ClassAndNamespace.Example>(): Subclass<ClassAndNamespace.Example>

πŸ’» Use Cases

When I have a complex class with a great number of associated methods and interfaces the most natural way of organizing seems to be namespaces for this project. It's a bit older and heavily uses globals but that won't be changing any time soon and so this is the most convenient way of being organized.

Unfortunately whenever classes are generic the hover hints become unwieldy and I'd prefer for them not to be.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Help Wanted You can do this Domain: Signature Help Information in editor tooltips when invoking a function call Experience Enhancement Noncontroversial enhancements and removed Domain: Signature Help Information in editor tooltips when invoking a function call labels Jan 9, 2025
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Jan 9, 2025
@RyanCavanaugh
Copy link
Member

I agree there's no need to print type parameters when qualifying the namespace of a type.

Showing the constraint as part of the signature in e.g. new Subclass() is intentional -- you (may) need that information to know how to correctly call the constructor.

@LukeAbby
Copy link
Author

LukeAbby commented Jan 9, 2025

Perfectly happy with showing the constraint, if you mean constructor Subclass<ClassAndNamespace.Example>(): Subclass<ClassAndNamespace.Example> that is. It's noted as my preference because it matches what goes on in other classes.

If you mean that it should still be constructor Subclass<ClassAndNamespace<T extends ClassAndNamespace.Example>.Example>(): Subclass<ClassAndNamespace.Example> I would find it odd to still show <T extends ClassAndNamespace.Example>. This is because if the namespace is named differently it will display as constructor Subclass<SomeOtherNamespace.Example>(): Subclass<ClassAndNamespace.Example> rather than constructor Subclass<ClassAndNamespace<T extends SomeOtherNamespace.Example>.Example>(): Subclass<ClassAndNamespace.Example>

@RyanCavanaugh
Copy link
Member

Right, when the name is part of a qualified thing like Foo.bar where bar can't see T, we don't need to show Foo<T>.bar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experience Enhancement Noncontroversial enhancements Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants