GithubHelp home page GithubHelp logo

Comments (20)

albertstill avatar albertstill commented on May 4, 2024 3

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

export-mike avatar export-mike commented on May 4, 2024 2

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.

bookercodes avatar bookercodes commented on May 4, 2024

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.

jeffmo avatar jeffmo commented on May 4, 2024

I'm trying to express (no pun intended) that express exports a function that returns an instance of class 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.

bookercodes avatar bookercodes commented on May 4, 2024

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.

bookercodes avatar bookercodes commented on May 4, 2024

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.

jeffmo avatar jeffmo commented on May 4, 2024

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.

alexeygolev avatar alexeygolev commented on May 4, 2024

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

ryyppy avatar ryyppy commented on May 4, 2024

I just realized that two people are working on the same express declarations... or am I mistaken?
See: #90

from flow-typed.

bassettsj avatar bassettsj commented on May 4, 2024

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.

ryyppy avatar ryyppy commented on May 4, 2024

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.

bookercodes avatar bookercodes commented on May 4, 2024

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.

bassettsj avatar bassettsj commented on May 4, 2024

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

export-mike avatar export-mike commented on May 4, 2024

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.

export-mike avatar export-mike commented on May 4, 2024

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.

patrykcieszkowski avatar patrykcieszkowski commented on May 4, 2024

@export-mike hey. I'm struggling with exact issue you came across. Did you find way around it?
image

from flow-typed.

export-mike avatar export-mike commented on May 4, 2024

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.

klauszhang avatar klauszhang commented on May 4, 2024

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.

klauszhang avatar klauszhang commented on May 4, 2024

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

export-mike avatar export-mike commented on May 4, 2024

@klauszhang Thank you I will take a look @albertstill ^ might be of interest to you.

from flow-typed.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.