расширение класса экспресс-запросов в Flow

Я создаю приложение nodeJS с помощью Flow, и мне нужно расширить экспресс-аннотацию по умолчанию для express $ Request, чтобы включить другие поля, которые я добавляю, например .user и .session.

К сожалению, когда я пытаюсь сделать это и создать промежуточное ПО, которое принимает этот новый тип запроса, Flow приходит в ужас, и я не уверен, что делаю не так.

исходный код для экспресс из потока типа:

declare class express$Request extends http$IncomingMessage mixins express$RequestResponseBase {
    ....
}

declare type express$Middleware = 
    ((req: express$Request, res: express$Response, next: express$NextFunction) => mixed) |
    ((error: ?Error, req: express$Request, res: express$Response, next: express$NextFunction) => mixed);

поэтому я подумал, что просто расширю express $ Request, и тогда все мое промежуточное ПО должно работать с новыми свойствами, верно?

declare class web$Request extends express$Request {
    user: any,
    isAuthenticated(): boolean,
    session: {
      loginForwardUrl: ?string,
    },
}

const authenticationMiddleware: express$Middleware = (
  req: web$Request, res, next
): mixed => {
  if (req.isAuthenticated()) {
    return next();
  }

  req.session.loginForwardUrl = req.originalUrl;
  return res.redirect('/auth/login/google');
}

к сожалению, это приводит к сверхсложной ошибке:

function
This type is incompatible with
union: function type(s): web/src/index.js:113
Member 1:
function type: flow-typed/npm/express_v4.x.x.js:97
Error:
web$Request: web/src/index.js:114
This type is incompatible with the expected param type of
express$Request: flow-typed/npm/express_v4.x.x.js:97
Member 2:
function type: flow-typed/npm/express_v4.x.x.js:98
Error:
web$Request: web/src/index.js:114
This type is incompatible with an argument type of
null: flow-typed/npm/express_v4.x.x.js:98

может кто-нибудь объяснить, что здесь происходит и как это исправить?

Благодарность!


person user358829    schedule 20.06.2017    source источник


Ответы (2)


Ошибка говорит о том, что ожидался аргумент / параметр типа express$Request (элемент 1) или null (элемент 2), но был замечен web$Request.

К сожалению, Flow не поддерживает расширение / переопределение типов flow / lib:

https://github.com/facebook/flow/issues/396

Я начал делать следующее:

  1. flow-typed install [email protected]
  2. Переместите express_v4.x.x.js из типизированного потока / npm / в типизированный потоком / (вне типизированного потока / npm /, чтобы он не был перезаписан будущими установками с типизированным потоком /, а внутри типизированного потока /, чтобы поток автоматически сделал declare blah операторы глобальными )
  3. Прямо под declare class express$Request... (так что его легко найти и выше того места, где он используется внутри declare module..., я поставил:

    declare class express$Request extends express$Request { user: any; isAuthenticated(): boolean; session: { loginForwardUrl: ?string; }; }

Я делаю это вместо того, чтобы помещать свои собственные реквизиты в исходный класс, чтобы было легко увидеть, какие реквизиты являются кастомными.

person Zachary Ryan Smith    schedule 28.09.2017
comment
oof, brutal - желаю, чтобы Flow поддерживал это лучше. Спасибо! - person user358829; 30.09.2017
comment
Где ты делаешь declare class? - person Shamoon; 11.09.2019
comment
@ user358829 может быть способ: см. twitter.com/yawaramin/status/1171954935082168321 - person Yawar; 12.09.2019
comment
@Yawar Я согласен, что это лучший способ, если я правильно понимаю (прошло много лет с тех пор, как я работал с Flow или Express). Учитывая файл в сущности, вы бы просто объявили тип своего маршрутизатора как TypedRouter, тогда все в порядке? - person Zachary Ryan Smith; 12.09.2019
comment
@Shamoon, см. Шаги 2 и 3. Но способ Явара может быть лучше. - person Zachary Ryan Smith; 12.09.2019
comment
Да, если вы используете TypedRouter вместо express$Router и используете соответствующие типизированные версии методов маршрутизации и объявляете все промежуточное ПО с правильными типами, тогда оно работает :-) например промежуточное ПО: function addSessionId(req: $Request & {-id: string}): void { req.id = 'random-id' }. Обратите внимание на -, которое делает id контравариантным полем расширенного типа объекта, то есть доступным только для записи. - person Yawar; 12.09.2019

Если вы предпочитаете не изменять исходный / npm / express_v4.xxjs с типом потока, вы можете использовать flow типы пересечений:

import type {$Request} from 'express';

type MyType = {
  foo: string
}:

export type CustomRequest = $Request & {
  foo: MyType | void;
  bar: string | void
};

Мне нравится этот подход, потому что я могу добавлять свои собственные определения типов в CustomRequest. Что может быть сложно при расширении $ Request внутри файла typed / npm / express_v4.x.x.js.

person lbodevan    schedule 01.12.2020