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

feat: add interface export to definition file #23

Merged
merged 4 commits into from
Apr 7, 2019

Conversation

Hammster
Copy link
Contributor

@Hammster Hammster commented Apr 5, 2019

Changes the behaviour for #22 while preserving the previous functionality


Closes #22

kleur.d.ts Outdated
@@ -42,4 +42,4 @@ interface Kleur {
}

declare let kleur: Kleur & { enabled: boolean };
export = kleur;
export default kleur;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a regression from #18 The way I understand is is that CommonJS exports have to be exported as export = FOO, since export default FOO would (in CommonJS terms) be exports.default = FOO explicitly.

I might be mistaken, but it's how I've made sense of it

Copy link
Contributor Author

@Hammster Hammster Apr 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what i know, the export = FOO and export let foo: Bar is necessary only for code generation, and not for type definition. I will do some additional testing in a CJS only environment to test the claim. Or maybe @marvinhagemeister has another idea or maybe a use case where the export default creates the ambiguity since it would affect some of my own projects as well 😨

Copy link
Contributor Author

@Hammster Hammster Apr 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay indeed it does not properly type the CJS required kleur with it. I will try to find a better solution for it 🙇 This happens when you get used to ESM 😅

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into it :)

FWIW, here's what I found about the differences: microsoft/TypeScript#7185

I believe it plays a role during ts-check and building your project, since it always has to know where modules' code is coming from & how to assemble it.

I think on your side, you need to do either of these:

import kleur = require('kleur');
// or
import * as kleur from 'kleur';
// or, pick colors
import { green, bold } from 'kleur';

Copy link
Contributor Author

@Hammster Hammster Apr 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've worked around it in my project by doing this in my definition file

import kleur from 'kleur'

export interface ITextStyle {
    indention: number
    padding: boolean
    styles: typeof kleur.bgBlack[] // Returns type Color
}

but i think i have got a idea on how to solve it, by defining a declare module "kleur/types" {} which can be imported in ts environments.

With the example of above it would be written like this

import { Color, Kleur } from 'kleur/types'

export interface ITextStyle {
    indention: number
    padding: boolean
    styles: Color[]
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should solve the issue i tested it with the following scenarios

  • const kleur = require('kleur')
  • import kleur from 'kleur'
  • import { Color, Kleur } from 'kleur/types'
  • and like this
import kleur from 'kleur'
import { Color, Kleur } from 'kleur/types'

function test (kleurInput: Kleur): Color {
  return kleur.bgBlack
}

@lukeed
Copy link
Owner

lukeed commented Apr 5, 2019

Hmm... this feels more complicated than it should be. The above import statements don't work for you?

What about doing this instead?

declare namespace kleur {
  interface Color {
    (x: string | number): string;
    (): Kleur;
  }

  interface Kleur {
    // Colors
    black: Color;
    red: Color;
    green: Color;
    yellow: Color;
    blue: Color;
    magenta: Color;
    cyan: Color;
    white: Color;
    gray: Color;
    grey: Color;

    // Backgrounds
    bgBlack: Color;
    bgRed: Color;
    bgGreen: Color;
    bgYellow: Color;
    bgBlue: Color;
    bgMagenta: Color;
    bgCyan: Color;
    bgWhite: Color;

    // Modifiers
    reset: Color;
    bold: Color;
    dim: Color;
    italic: Color;
    underline: Color;
    inverse: Color;
    hidden: Color;
    strikethrough: Color;
  }
}

declare let kleur: kleur.Kleur & { enabled: boolean };
export = kleur;

Of course I don't have your full setup here, but it seems to work locally. I have access to the Color and Kleur interfaces thru the kleur namespace.

Screen Shot 2019-04-05 at 2 55 56 PM

@Hammster
Copy link
Contributor Author

Hammster commented Apr 5, 2019

That would be a alternative solution that I was also trying, it works fine in my examples too. But it would change the usage, which could lead to confusion since kleur.bgBlack is on the same object as kleur.Color from a syntax perspective, excluding autocomplete that is.

import kleur from 'kleur'

function test (kleurInput: kleur.Kleur): kleur.Color {
  return kleur.bgBlack
}

@lukeed
Copy link
Owner

lukeed commented Apr 6, 2019

Hey sorry – had to step out early yesterday.

Not sure what you mean by this:

since kleur.bgBlack is on the same object as kleur.Color from a syntax perspective

Do you mean for the import statement?

I'll wait to hear from you but as of right now, despite learning something new from this PR, I prefer the solution I pasted since I'm familiar with that setup & IMO it feels a lot weirder to have a separate kleur/types module to both know about and import from. I also haven't seen this practice anywhere else (that I know about)

@Hammster
Copy link
Contributor Author

Hammster commented Apr 7, 2019

No pressure 😉

The changes your proposed are now in the PR.

I was talking about the part that namespace and export share a name, and what happens to the namespace when you rename the import. But I tested it and indeed the namespace name gets also changed.

eg:

import kleurRenamed from 'kleur'

function test (kleurInput: kleurRenamed.Kleur): kleurRenamed.Color {
  return kleurRenamed.bgBlack
}

Thank you so much for giving me a much better insight into TS definitions, I really had some misunderstandings and learned a good chunk of new stuff.

@lukeed
Copy link
Owner

lukeed commented Apr 7, 2019

Likewise! I hadn't realized you could declare sub/multiple modules within a definition file.

Thanks so much @Hammster, especially for going thru the back-n-forth :)

@lukeed lukeed merged commit 70e682d into lukeed:master Apr 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants