colors.js icon indicating copy to clipboard operation
colors.js copied to clipboard

index.d.ts is polluting the global String interface

Open craigkovatch opened this issue 6 years ago • 14 comments

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.

craigkovatch avatar Sep 19 '18 00:09 craigkovatch

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...

DABH avatar Sep 19 '18 01:09 DABH

@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.

craigkovatch avatar Sep 19 '18 02:09 craigkovatch

How about custom theme?

kamontat avatar Sep 23 '18 08:09 kamontat

You might need to add

interface String {
  strip: string;
  [key: string]: string;
}

kamontat avatar Sep 23 '18 08:09 kamontat

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

craigkovatch avatar Sep 23 '18 14:09 craigkovatch

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!

DABH avatar Sep 26 '18 20:09 DABH

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.

craigkovatch avatar Sep 26 '18 21:09 craigkovatch

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

DABH avatar Sep 26 '18 21:09 DABH

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!

craigkovatch avatar Sep 26 '18 21:09 craigkovatch

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... :)

DABH avatar Sep 26 '18 21:09 DABH

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

Marak avatar Sep 26 '18 22:09 Marak

Good point! I will investigate and get back.

craigkovatch avatar Sep 26 '18 22:09 craigkovatch

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

craigkovatch avatar Oct 01 '18 23:10 craigkovatch

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

demedos avatar Nov 24 '22 09:11 demedos