Comments (20)
@export-mike not sure if this is the perfect solution but we declare a global class that extends express$Response
for the custom server timing functions we add to the response object in a middleware:
declare class customExpress$Response extends express$Response {
setMetric(): void;
startTime(string, string): void;
endTime(string): void;
}
Then a controller or middleware function may have this signature (req: express$Request, res: customExpress$Response) => {
.
from flow-typed.
Trouble is now I'm getting flow errors when I pass in a express handler which uses custom request object types that extend express$Request. As express types are not matching to the base type of express$request
const express = require('express');
declare class session$Request extends express$Request {
session: { [key: string]: mixed }
}
const app = express();
app.use((req: session$Request, res: express$Response, next: express$NextFunction): mixed => {
req.session.user = { id: 2 };
next();
});
app.use((req: express$Request, res: express$Response, next: express$NextFunction): void => {
next();
});
cc: @albertstill
from flow-typed.
I'm having a spot of bother 😫. Can someone please help me?
In my Flow definition file I have the following code:
declare class Express {
}
declare var exports: () => Class<Express>;
I'm trying to express (no pun intended) that express
exports a function that returns an instance of class Express
. I kindof did that...
... But I would expect Flow to complain that the use
and post
functions (seen in the first screenshot) are not part of the Express
class. Moreover, when I actually do declare a function on the Express
class, Flow doesn't seem to recognize it from within my source files. For example, if I were to define a method called something
:
declare class Express {
static something(someNumber: number): void;
}
I could pass a string
or null
or anything (or nothing) to something
and Flow wouldn't mind 😱.
I'm obviously misunderstanding something here. Can someone please help me? Thanks.
from flow-typed.
I'm trying to express (no pun intended) that
express
exports a function that returns an instance ofclass Express
If you want to refer to an instance of a class, you just use the class name:
declare module "express" {
declare class Express {
instanceMethod() {}
static staticMethod() {}
}
declare module.exports: () => Express;
}
import express from "express";
const app = express();
app.instanceMethod(); // Valid
app.staticMethod(); // Error
(Note also that I used declare module.exports
here instead of declare var exports
. The latter is deprecated in favor of the former -- starting in Flow v0.25 -- so might as well switch to the latest syntax while we're at it :) )
from flow-typed.
Many thanks for your response, @jeffmo. Unfortunately I'm still struggling.
All in all express.js.flow
now looks like this:
declare module "express" {
declare type NextFunction = (error?: Object) => void
declare class Request {
headers: {[key: string]: string};
}
declare class Response {
status(statusCode: number): Response;
json(body: any): Response;
}
declare class Express {
}
declare module.exports: () => Express;
}
When I run flow
on this code:
import express from 'express'
const app: express.Express = express()
app.post('/foo', function(req, res) {
// ...
})
... I still get no errors:
(express.Express
doesn't have a post
function so I should get an error)
I'm a bit confused by your snippet:
import express from "express";
express.instanceMethod(); // Valid
express.staticMethod(); // Error
Aren't you exporting a function that returns an instance of Express
, not an Express
object when you write declare module.exports: () => Express;
?
Thanks.
from flow-typed.
Somehow when I omit the type (i.e. const app = express()
instead of const app: express.Express = express()
) things work 😮.
Things also work if I declare class Express
outside the "express"
module and write const app: Express = express()
.
I think I can start to make some more progress now 🎉
I would still ❤️ to understand why this is the case if any one cares to explain! Thanks.
from flow-typed.
Aren't you exporting a function that returns an instance of Express, not an instance of Express when you write declare module.exports: () => Express;?
Oops! I typo-ed that... Just edited my post to reflect this.
(I'll dig in to the rest tomorrow when I have a chance to look closer)
from flow-typed.
@alexbooker: what I think might be happening here is express.Express being treated by flow as something else rather than what you want it to be. To check it try to do something like
const test: express.Express = 1
and then run flow in your terminal to see the exact error (what it compares to what).
You shouldn't use static
for method definitions because they are not really static methods. As you know what happens when you do express()
is the createApplication
factory initialising whatever it needs and returning you an 'instance' off app with all the use
, get
, post
methods. So you're almost there.
declare module "express" {
declare type NextFunction = (error?: Object) => void
declare class Request {
headers: {[key: string]: string};
}
declare class Response {
status(statusCode: number): Response;
json(body: any): Response; //as far as I remember json method uses stringify underneath which
// means that you would want to check you object here so it want crash
// your JSON.parse on the other end. If it's possible obviuosly
// At least it should be Object | Array<any>
}
declare class app {
}
declare module.exports: () => app;
}
You don't need to annotate your app unless you're writing a test for your declarations. Flow will infer it without a problem.
On the other hand if you do want to test your declarations I believe you should make your Express type global... or import it as a type. This part is a bit confusing in the docs. So maybe @jeffmo could shed some light when he has a minute.
The question is — if you need the type from a module in your declaration file how would you get ahold of it.
from flow-typed.
I just realized that two people are working on the same express declarations... or am I mistaken?
See: #90
from flow-typed.
I have been trying to work on it for a while, I am pretty close, but I have problems with the request handler callback signature that determines the type of the first params based on if it is an error handler or a normal request handler. I could use some help over on #90
from flow-typed.
I know your feels,... sometimes it's hard to do overloaded functions with optional first parameters.... with tape
in some cases I am forced to annotate the test(...)
function to make flow recognize the last parameter to be a function with test-context... not sure how to deal with this...
Here is what I mean: https://github.com/flowtype/flow-typed/blob/master/definitions/npm/tape_v4.5.x/test_tape_v4.5.x.js#L57
So right now I don't have a solution for this... there is probably an open issue on flow for this specific case... it's hard to find tho.
from flow-typed.
I just realized that two people are working on the same express declarations... or am I mistaken?
See: #90
No, I think you're right 😄
@bassettsj is doing a great job and I'm actually going to close this issue in favour of his PR 👍
from flow-typed.
@alexbooker I would love to get more help, I left some comments on where I am stuck at the moment, so please feel free to add suggestions there. 😄
from flow-typed.
Hi!
Thanks for the flow-type file for express v^4.0.0
I am adding custom properties to req and res which is a common pattern with express to pass around system wide things. I'm finding it overly complicated to add my own fields to req and res. whats the recommended approach? extend the $Request, $Response types? Or directly edit the flow-typed file?
for example:
type User = { id: number};
app.use((req:$Request, $Response, next: NextFunction) => {
const user: User = {id: 123};
res.user = user;
});
app.get('/',(req:$Request, $Response, next: NextFunction) => {
res.send(`Hi userId: ${res.user.id}`);
});
Flow Error:
property `user` Property not found in express$Request
from flow-typed.
cheers @albertstill I'll give this a try!
I've since been using the spread syntax which seems to work for most cases.
type User = { id: number};
type Request = {
...$Request,
user: User
}
Update this doesn't seem to carry over req.params and query etc.
so I'm using the class extends method described by @albertstill instead 👍
from flow-typed.
@export-mike hey. I'm struggling with exact issue you came across. Did you find way around it?
from flow-typed.
best method is to use // $FlowFixMe inline of your app.use statements. I gather I'm more likely to make a typing error when writing a handler.
from flow-typed.
Hello, thanks for the definition file!
it works great, only there's a little issue I have and cannot resolve.
if i do
import express, {Express} from 'express';
flow will complain that
[flow] Named import from module `express` (This module has no named export called `Express`.)
I can find this export in .d.ts file but not in flow typed file. Is it missing or something?
Thanks!
from flow-typed.
@export-mike
Hi, I might have a solution to your request issue, have a try of:
import type {$Request} from 'express'
const middleware=(
req:$Request & {session:{[key:string]:mixed}}
, ...)=>{...}
it is called intersections
from flow-typed.
@klauszhang Thank you I will take a look @albertstill ^ might be of interest to you.
from flow-typed.
Related Issues (20)
- rimraf is missing v4/5 HOT 1
- Workspace key is missing in the v4 docs
- Defintion koa-path-match
- Jest missing test case timeout HOT 2
- Dependency's dependency definitions should only consider `dependencies` HOT 1
- base-64
- add definition for body-scroll-lock-upgrade
- Add use-debounce definition
- [Question]: How to fix flowgen test after flow update HOT 1
- webpack v5 missing ProgressPlugin
- Jest support node api functions
- react-native loaded into test runner HOT 2
- use-debounced useDebounceCallback needs improvement
- body-scroll-lock-upgrade is declared wrong
- axios is missing signal property in config HOT 1
- new definition module-alias
- faker needs to add `person` from v8 onwards
- Add `worker_threads` to node environment
- Axios missing `instance.interceptors.request.clear()`
- Jest is missing toHaveBeenNthCalledWith HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from flow-typed.