Marak / colors.js

get colors in your node.js console
https://github.com/Marak/colors.js
Other
5.17k stars 446 forks source link

index.d.ts is polluting the global String interface #243

Open craigkovatch opened 6 years ago

craigkovatch commented 6 years ago

The typings for this library are polluting the global String interface. In every package which consumes (directly or indirectly) this package, every String is getting a bunch of extra noise in the autocomplete results.

declare global {
    interface String {
        strip: string;
        stripColors: string;

        black: string;
        red: string;
        green: string;
        yellow: string;
        blue: string;
        magenta: string;
        cyan: string;
        white: string;
        gray: string;
        grey: string;

image

If it's relevant this is VS Code 1.27.2, TypeScript 2.8.3.

I believe this was caused by this commit in February 2018: 08ce9159f4f2af07f4c631ba10fbecc16190b00a

Specifically, pulling the typings into your library in this way means that they are exposed to indirect consumers, rather than explicitly pulled in by direct consumers via the @types packaging. I suggest returning to the previous method, e.g. via DefinitelyTyped.

DABH commented 6 years ago

Interesting regarding the indirect imports. I wonder if there is a clean way to just change something in the definitions file so only direct imports are affected. I’ll have a think about this, but I’m not opposed to moving to DefinitelyTyped if there is no viable alternative. (Though one wonders if that would really solve the problem — if I import a package that depends on @types/colors, wouldn’t my String also get polluted?) Some examples to play with would probably be useful here...

craigkovatch commented 6 years ago

@types/* dependencies are devDependencies, so they aren't pulled into the published package artifact. In this case you're publishing your typing file along with your library, which to my knowledge isn't bad practice per se, but when combined with the global extension of String leads to this pollution. In other words, a package which depends on @types/colors would not pull @types/colors along for the ride, it would only use it for its own local build. Including it in your main package is the source of the pain.

My understanding of this package is that the extension of String.prototype is considered one of the primary features. If that's the case, moving back into DefinitelyTyped, or at least a separate package for just your index.d.ts file, is the only solution that I can see.

kamontat commented 6 years ago

How about custom theme?

kamontat commented 6 years ago

You might need to add

interface String {
  strip: string;
  [key: string]: string;
}
craigkovatch commented 6 years ago

@kamontat that would completely remove all member type safety from the global String interface.

DABH commented 6 years ago

Hey @craigkovatch sorry for delayed reply. The thing I want to clarify is -- is the current behavior correct? For example, .cyan popus up in autocomplete, but does that actually work? In other words, are the autocomplete suggestions misleading/incorrect, or are they correct but just annoying? If it's the latter, have you tried a vanilla Node-style import of colors, e.g. const colors=require('colors') (which I think ignores typings), instead of e.g. import * from 'colors' (which I think will pull in the typings)? Let me know what you think!

craigkovatch commented 6 years ago

My package doesn't use colors, that's the problem :) My package consumes a package which consumes a package which consumes colors, but because these typings are written against the global String interface I have no ability to "mute" them.

Your typings are correct AFAIK, but I've never actually used your package :) From the documentation I've read, if the package deep in my tree used colors/safe rather than colors, I wouldn't have this issue. But I don't have control over that, and fixing it by forcing the typings to be an intentional, build-time inclusion is the only way I can see to fix it in one place rather than hoping hundreds of other people get it right. LMK if you think I'm missing something, though.

For now I've fixed this in my package by overriding to colors 1.1.2, i.e. the last release before 08ce915. But that's...less than ideal.

DABH commented 6 years ago

Fair enough -- sigh :) Will work on getting the typings back into DT for the next release.

craigkovatch commented 6 years ago

It would probably be worth asking someone on that side if they have other ideas. I'm not claiming to be the world's expert or anything :) I think what you're doing here is indeed the recommendation by Microsoft for TypeScript, but this package is an extreme edge case in that colors wants both to extend String.prototype and it's a low-level util library, so likely to be deep in the dependency tree. That's why I think @types/colors is the right-and-only choice here. But if there is another way, I'd be happy to learn it!

DABH commented 6 years ago

Agreed -- the best practice is indeed to include typings in the repo whenever possible for TS, but most packages don't extend JS prototypes. And while it's correct still, it's definitely annoying if you're building an app that has nothing to do with colors but still sees all those extra typings (if it weren't in the global namespace, like most packages, you wouldn't see the typings). So, I think this is a valuable discussion! A lot of this is an art not a science... :)

Marak commented 6 years ago

I'm not really using TypeScript myself so I'm not able to offer a good solution for this.

Is there anyway we can programmatically switch the TypeScript imports based on whether or not the String.prototype code is loaded?

I agree with @craigkovatch in that having all these overloaded string methods popup unexpectedly in VS Code is not ideal, but it is to my understanding that in his case String is actually being overloaded, so the TS definitions that appear are correct?

Generally I'd like to go for the least surprising behavior for all users. If you've depended on a package that does require('colors') and not require('colors/safe'), it probably shouldn't be surprising if the Types are loaded on String as well.

No reply needed for me. Hope this helps. Let me know if you need help making a decision @DABH

craigkovatch commented 6 years ago

Good point! I will investigate and get back.

craigkovatch commented 6 years ago

@Marak @DABH no, it would not appear that String is overloaded at runtime. This issue is just about pollution of typings.

demedos commented 1 year ago

I see this has been an issue for a very long time; is there any plan to fix it? Maybe I can help with that if we come up with an idea of how to do so