express-rate-limit / express-rate-limit

Basic rate-limiting middleware for the Express web server

Home Page:https://npmjs.com/package/express-rate-limit

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TypeScript typings and tests

nfriedly opened this issue · comments

Currently, the typescript typings are untested, which allows releases to go out with mistakes. To remedy this, either the current tests could be converted to typescript, or new tests could be written in typescript that just validate the interface.

I'm not looking to switch the library itself to typescript at this point, although I'm not against that in principle.

This relates to #65 / #119 and #136 / #137

Update: the typescript typings were removed from v5.0.0 and moved to the typescript branch. I'll merge them back into master and publish a new release once they're tested and fixed.

Just got bit by this today, had it working on 3.4.1 but upgraded to 4.0.1 today.

Type 'typeof import("node_modules/express-rate-limit/index")' has no compatible call signatures.

In the meantime I've just changed my calls to (rateLimit as any)({ ..config object.. })

Ouch, I'm sorry. Is that something that you know how to fix? I've basically never used type script, but I know a lot of people that use this library use it, so I do want it to be supported better.

It's not big deal, I don't write many definition files so I'm not familiar with how to structure it. Looking at the history this error shouldn't have happened in the first place so it's probably just something up with my configuration.

Hi, anybody found a solution?
getting this error with 4.0.1

you have to do something like this [edited]:

import * as RateLimit from 'express-rate-limit';

and then use @ts-ignore above.. it's a quick and dirty fix i think

Agree with @derSoerrn95, it worked but kind of dirty solution

Sorry guys. I 've never really done anything with TypeScript. I merged in the initial PR to add typings without realizing there'd be this much trouble. Now, 6 PRs later, folks are still having issues. I knew I didn't know how to use TS properly, but it seems like no one else does either :(

At this point, I'm thinking I might just remove the index.d.ts file, it doesn't seem to be worth the trouble.

@nfriedly index.d.ts isn't currently using valid typescript. Change https://github.com/nfriedly/express-rate-limit/blob/master/index.d.ts#L39 to:

export interface RateLimit {
  (options?: Options): (req: Request, res: Response, next: NextFunction) => void;
}

I'll tell you what. If you'll put that in a PR and include a test that shows it working, I'll take it.

A quick non-breaking(/snooze) option (until we figure it out) would be to instead of removing index.d.ts to just add declare module 'express-rate-limit' in there. In this case at least then tsc wouldn't complain.

As much as I think adding test would resolve future issues we need to restore functionality, because adding tests would require including typescript into the test pipeline.

We should fix the index.d.ts and then ensure future changes are tested.

The trouble is that I have no confidence that we can get it right on the 7th attempt after the first 6 failed, and I'm tired of essentially "testing on production". It's embarrassing, and I shouldn't have done it to begin with.

So I'm going to remove the index.d.ts file for now and create a new branch where we can experiment without thrashing the latest npm version. Once it's both correct AND tested, I'll merge it back in. In the meanwhile, folks can go back to whatever is in definitely typed.

v5.0.0 is now on npm without the index.d.ts.

I went ahead and merged in @KevinKrug's PR, #146 into the typescript branch. You can try it out by installing from github:

npm install git://github.com/nfriedly/express-rate-limit.git#typescript

Once it's tested and I'm confident that we got the typings right, I'll merge it back into master and publish a new npm release.

People who contributed to the typescript typings so far: @googol, @jason-han-nue, @Diluka, @derSoerrn95, @AnandChowdhary:

First of all, I wanted to say thank you! I do appreciate your contributions, and I know many others do also.

Second, since many of you wern't in this thread, I wanted to make you aware of what was going on here. As I said, I do appreciate your work, but I have decided to remove it for the short-term while we get some issues sorted out and get some proper automated testing in place. I do, however expect to restore it in the future.

@nfriedly thanks for merging in my PR, however it was missing the export declaration..(❗️ ) added another PR against the typescript branch to add this! #147

@nfriedly i tested my fork git://github.com/kevinkrug/express-rate-limit.git#bugfix/RateLimit-Typefix witihin one of our node-ts projects, and ts compilation is passing. As for writing tests, I hope to get to it this week, cheers.

I went digging and noticed that the definitely typed index.d.ts has a namespace similar to what @KevinKrug added #147, but they put most of the other definitions inside of the namespace: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express-rate-limit/index.d.ts - is that something we should do?

I also noticed the return type is express.RequestHandler; which isn't exactly correct, since we add a resetKey and resetIp methods onto the returned object, but might be a good base interface to extend from (can you do that with a typescript definition?). It looks like the current index.d.ts is also missing those methods.

@nfriedly yeah good points!

  • as for the namespace, using namespace is now the preferred way to declare internal modules (as of TS 1.5), grouping related interfaces within the namespace could make sense. Basically every module creates a namespace. Here, I just declared the namespace (/the module) and then the export (which is just the RateLimit function). (as there are no properties/methods being added to the namespace, however nesting the interfaces within the namespace declaration sounds good!)

  • interfaces can extend other interfaces in TS, no prob. so i’ll update the return type as per your suggestion

@nfriedly fyi. pushed your suggested changes to my fork kevin-krug@1b3e876.

@KevinKrug namespaces are not recommended practice anymore, except for backwards compatibility and more difficult typing cases

I'd suggest making the breaking change of using a named export instead of exporting the function as module.exports, in which case the best-practice es module syntax could be used in typescript.

In fact, it could be made as a non-breaking change by adding the function as a property of itself, and just not exposing the default export in typescript:

function rateLimit() { }
module.exports = rateLimit // js users can still do const rateLimit = require('express-rate-limit')
module.exports.rateLimit = rateLimit // or const { rateLimit } = require('express-rate-limit')
export interface X { }
export function rateLimit() // TS users will import { rateLimit } from 'express-rate-limit'

Yea, I prefer the non-breaking change. Does typescript have a way to describe both?

Sadly no. If we go with module.exports = something then we need to choose between the two.
However with current bundlers and node, if we also add module.exports.default = rateLimit, we can also add export default rateLimit to the definitions, and then import via either import { rateLimit } from 'express-rate-limit' or import rateLimit from 'express-rate-limit'.

It does get more hacky though, so I'm not sure if that's worth it. Any TS users should have no problem adjusting to the named export

What is the progress on the typescript branch being merged? @types/express-rate-limit has outdated typings (v3.3) so currently there are no official typings. I am willing to help with the merge.

Hi @shilangyu,

I think it's just in limbo right now because no one has had the time/interest/etc. to finish it.

I'd love to have the help if you're ready to jump in. The main requirements I had in mind were:

  1. Automated testing of the TypeScript typings
  2. It can't break things for current users

I shiped six versions that didn't meet either of those requirements before I reverting and moving everything to a branch. I'm starting to wonder if it's even possible to have a complete, accurate type script typing that doesn't break the current users. The other option is, I suppose, to ship it as a semver major release if the breakage is truly unavoidable.

I think a good starting point might be to copy in exactly what is in the definitely typed repository, and then just update that with anything that it's missing, rather than starting from scratch as we did here.

Or you could send a PR to definitely typed. Presumably they are better than I am being able to tell what will cause trouble and what's safe, so sticking with their typings might just be the best option at this point.

Typescript coders got used to using Definitely Typed (first thing i did) as type definitions, so i think its better to stick to that. Im surprised it has outdated types considering express-rate-limit is a fairly popular package (i guess its because there was no need as a .d.ts file existed here?). I have however 0 experience with types testing. If i find time i will send a PR to Definitely Typed.

Here's one approach: convert the codebase to typescript and generate the types automatically from that. The compiler will take care of testing the types.

#152

I went ahead and merged #152 into the typescript branch and published it under a typescript dist tag.

Can everyone here test it out and let me know if you hit any issues?

npm i express-rate-limit@typescript

I'm calling out a few other people who I believe use typescript to ask for help with testing this release: @SimonSchick, @gangsthub, @xaiyeon, @andreGarvin, @zuohuadong, @johannesschobel, @oxala, @juergenzimmermann, @jecsham, @sliktrik, @bendavies99

Would each of you please install this pre-release build of express-rate-limit and confirm that it works for your apps?

npm i express-rate-limit@typescript

Hi,

got following error:

node_modules/express-rate-limit/dist/express-rate-limit.d.ts:13:9
    13         message: string;
               ~~~~~~~
    The expected type comes from property 'message' which is declared here on type 'Partial<Options>'

    at createTSError (/Users/xxx/IdeaProjects/xxx/node_modules/ts-node/src/index.ts:245:12)
    at reportTSError (/Users/xxx/IdeaProjects/xxx/node_modules/ts-node/src/index.ts:249:19)
    at getOutput (/Users/xxx/IdeaProjects/xxx/node_modules/ts-node/src/index.ts:362:34)
    at Object.compile (/Users/xxx/IdeaProjects/xxx/node_modules/ts-node/src/index.ts:395:32)
    at Module.m._compile (/Users/xxx/IdeaProjects/xxx/node_modules/ts-node/src/index.ts:473:43)
    at Module._extensions..js (internal/modules/cjs/loader.js:816:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/xxx/IdeaProjects/xxx/node_modules/ts-node/src/index.ts:476:12)
    at Module.load (internal/modules/cjs/loader.js:672:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:612:12)
    at Function.Module._load (internal/modules/cjs/loader.js:604:3)

But really nice that u're trying to help ts users.

oh sorry, it was my fault :D I was using an object instead of string.. Would you change the the message field type into message: string | any?

So when I'm using a string it works.

Good catch @derSoerrn95!

Yes, options.message should be anything that express's res.send() accepts:

res.send([body])

Sends the HTTP response.

The body parameter can be a Buffer object, a String, an object, or an Array.

It looks like it's an optional parameter, so in effect it can also be undefined.

So.. this is strange. I believe I know how to fix your issue, just change this to any: https://github.com/nfriedly/express-rate-limit/blob/d2272083cedcb710a52d4f988aca1c72686ffcd6/lib/express-rate-limit.ts#L17

But I wanted to have a test to be sure, and I realized that none of the tests are in typescript yet. So, I set things up and wrote the test and.. it's passing. With no changes to the code. Can anyone explain why this doesn't fail at the compilation stage? https://github.com/nfriedly/express-rate-limit/blob/d2272083cedcb710a52d4f988aca1c72686ffcd6/test/typings-test.ts#L6-L8

Yeah I totally forgot that the message can be anything, sorry. I just took the type from the default message

I'll check out how the codebase looks after your changes romorrow and look at what might be behind the test compilation problem. If you have a branch with that test I can check it out directly too if you push it

@derSoerrn95 what version of typescript are you using? I'm on 3.5.2

npm ls typescript

I posted to Stack Overflow, because I'm completely stumped as to why this isn't failing for me: https://stackoverflow.com/questions/56989794/why-is-typescript-not-throwing-an-error-here

Nevermind, the folks on SO were able to explain it. The basic issue was that typescript only checks import statements and I had done a regular node.js-style require(). Fixed now, and published in a new beta:

npm i express-rate-limit@typescript

Are there plans on merging typescript branch into master?

Yes, once I'm satisfied with it. There still aren't any tests except for the two message type ones that I just fixed today. I think the existing JS tests should probably all be migrated to TS in order to exercise the types, and we should probably make sure that the other issues that users had with the recent releases are all tested for also.

holy sh*t.. i didn't get, that there is a rewrite completely in TS.. that is awesome man!

Beta 7 published to npm with @googol's changes from #157 and some testing improvements I added. As before, please test it with:

npm i express-rate-limit@typescript

I have hit one issue that perhaps someone here can help with: How can I mock setInterval for a test in TypeScript? More details here: https://stackoverflow.com/questions/56998183/how-can-i-overwrite-setinterval-with-a-mock-for-a-test-in-typescript

I always use sinon fake timers.

Yea, I looked at that, but this test is a little different - we don't actually care about the time that elapses, we just care about the return value from setInterval - in node.js, it's an object with a few methods, but in Electron (and browsers), it's a number. I don't think sinon nor the underlying lolex library support mocking that.

https://github.com/nfriedly/express-rate-limit/blob/0ca96669ae188a5bd7e5bc97a712ba588914b423/test/memory-store-setinterval-test.js#L19

That one's a bit tricky, typescript doesn't like you changing the globals.

One approach that I think might be helpful would be to create a setTimeout variable in the ratelimit constructor, with an explicit type that returns either a Timeout or a number and assign the global setTimeout to that. Then where the settimeout is used, you'd always be forced to check which type the return value has before using it, making it safe, and if the global setTimeout has some weird type because of some library typings it would fail there

const localSetTimeout: (callback: ()=> void, delay: number) => number | Timeout = setTimeout;

const timer = localSetTimeout(() => {}, 5000);
if (typeof timer !== 'number') {
  timer.unref();
}

@johannesschobel it wasn't planned, I just did it on a whim on a boring afternoon :D

Any news for when this typescript beta branch will be merged into master? I'm converting an old project from js to ts, and would prefer not to have to use a beta version.

@IamFlowZ that's a good question; I kind of forgot about this (sorry). Have other folks here been using this branch?

Also, there have been a few small improvements to master since this was branched - would anyone be willing to port those over?

If I get some time in the next week or so I could look into it.

@IamFlowZ that's a good question; I kind of forgot about this (sorry). Have other folks here been using this branch?

Also, there have been a few small improvements to master since this was branched - would anyone be willing to port those over?

I can do it. I have forked the repo and on a clean install on the typescript branch 8 tests fail, have they not yet been implemented or something is not right?

Still broken?

Still broken?

No, just never completed. You're welcome to pick up the torch and carry it forward though :)

Thanks to the work of @googol, @gamemaker1, and others, this library has been fully converted to typescript and published to npm in v6.0.0: https://www.npmjs.com/package/express-rate-limit

still getting the error

const limiter = rateLimit({
                         ^
TypeError: (0 , express_rate_limit_1.default) is not a function

version 6.0.3

import rateLimit from "express-rate-limit";

Hi @nichitaa,

Could you please open a new issue using the bug report template, so we can help out?

Thanks