sindresorhus / debounce

Delay function calls until a set time elapses after the last invocation
Other
798 stars 80 forks source link

Allow ES-style import { debounce } from "debounce"? #20

Closed JoshuaKGoldberg closed 6 years ago

JoshuaKGoldberg commented 6 years ago

As this module works now, it violates ES6/ES2015-style module export rules. See this SO question and answer for why TypeScript cares and this bug on DefinitelyTyped for additional reasoning why it's inconvenient to users.

To not break the existing const debounce = require("debounce"); for users, I propose the object be given a .debounce member so we can also import it using const { debounce } = require("debounce"); (or var debounce = require("debounce").debounce; for the traditional folks).

dortamiguel commented 6 years ago

Yes, I can't use this with imports

senyaak commented 6 years ago

Import works for me with typescript/webpack.

Szmiglo commented 6 years ago

@senyaak How did you managed it to work? I'm also working with TS + webpack and using import { debounce } from 'debounce'; gives me error

Could not find a declaration file for module 'debounce'. '...\node_modules\debounce\index.js' implicitly has an 'any' type.

bsg62 commented 6 years ago

Just remove the curly brackets: import debounce from 'debounce'

Debounce has only a default export with module.exports, so you can't use the curly brackets to import certain functions or variables. Take a look at MDN.

Szmiglo commented 6 years ago

@bsg62 doing what you've suggested also gives me the same error. Only const debounce = require('debounce'); works correctly

bsg62 commented 6 years ago

@Szmiglo Okay, I think I have a solution. I was under the impression, that TypeScript imports work the same as ES6 imports, but that's not the case. My example from above works fine with ES6 and Webpack, but not with TS.

This should work: import * as debounce from 'debounce'

Szmiglo commented 6 years ago

Still the same error :(

bsg62 commented 6 years ago

Well, okay, I'm blind. :D

The import works fine, but TypeScript can't find a type declaration for debounce.

You can either disable noImplicitAny in your TS config or create a definition, as suggested here.

JoshuaKGoldberg commented 6 years ago

create a definition, as suggested here.

Alas, that isn't a workable or future-proof solution. ☹

There's a good reason why TypeScript refuses to acknowledge the type declaration for debounce: what it's doing isn't compatible with ES modules, only CommonJS. ES modules don't allow the exported object to be callable (a function). It can contain members that are functions, but it itself must be an object.

This will not work in systems that properly implement the new spec:

import * as debounce from "debounce";

// This should give an error about not being callable
debounce(...);

...while this is allowed and encouraged:

import { debounce } from "debounce";

debounce(...);

Links in the OP for why this is the case.

ChuckJonas commented 6 years ago

In ts 3.0.3, when I try import { debounce } from "debounce"; I still get an error [ts] Module '"/Users/jonas/Documents/code/apex-pmd/node_modules/@types/debounce/index"' has no exported member 'debounce'..

If I update the types.d.ts file to look like this it works:

export declare function debounce<A extends Function>(f: A, interval?: number, immediate?: boolean): A & { clear(): void; };
JoshuaKGoldberg commented 6 years ago

@ChuckJonas yup, the problem there is that the debounce package was updated but your TypeScript typings in the @types/debounce package were not.

https://github.com/DefinitelyTyped/DefinitelyTyped/pull/29768

Once that PR is merged, as soon as a new version of @types/debounce is published (normally within a few hours) it'll have the right change.