How to specify a Moment.js object annotation in Flow
Asked Answered
T

2

22

I'm currently learning Flow by applying it to an existing project and looking to annotate function parameters as a Moment.JS objects.

Using flow-typed I was able to install a library definition for Moment.JS which appears to have the type I'm looking for:

declare class moment$Moment {
  static ISO_8601: string;
  static (string?: string, format?: string|Array<string>, locale?: string, strict?: bool): moment$Moment;
  static (initDate: ?Object|number|Date|Array<number>|moment$Moment|string): moment$Moment;
  static unix(seconds: number): moment$Moment;
  static utc(): moment$Moment;
  ...

However when I try to annotate function parameters as Moment.JS objects, Flow fails to recognize them as such. In the following function startDate and endDate are Moment.JS date objects.

const filterByDateWhereClause = (startDate: Moment, endDate: Moment): string => {...};

Flow gives the following error:

const filterByDateWhereClause = (startDate: Moment, endDate: Moment): string =>
                                                 ^^^^^^ identifier `Moment`. Could not resolve name

Is this even possible with Flow? Or do I need to duplicate the type for the Moment.JS object identical to the one in the library definition provided by flow-type? I'd prefer not to do this as the libdef is fairly lengthy.

For example:

declare class Moment {
  static ISO_8601: string;
  static (string?: string, format?: string|Array<string>, locale?: string, strict?: bool): moment$Moment;
  static (initDate: ?Object|number|Date|Array<number>|moment$Moment|string): moment$Moment;
  static unix(seconds: number): moment$Moment;
  static utc(): moment$Moment;
  ...

const filterByDateWhereClause = (startDate: Moment, endDate: Moment): string => {...};

What am I missing?

Thirtieth answered 27/3, 2017 at 1:37 Comment(0)
H
41

There are three ways to get the type you want.

If your file already require's moment as a module you should be able to use that type

import moment from 'moment';

const filterByDateWhereClause = (startDate: moment, endDate: moment): string => {...};

or if you don't use the source but just the type within your file.

import type Moment from 'moment';

const filterByDateWhereClause = (startDate: Moment, endDate: Moment): string => {...};

You can do this because that's what the libdef specifies as the module export: https://github.com/flowtype/flow-typed/blob/7822da72587078a4b8e0f2b56746d0da41a3ddde/definitions/npm/moment_v2.x.x/flow_v0.34.x-/moment_v2.x.x.js#L233

Alternatively, it looks like that libdef declares a type moment$Moment in the global namespace too so you can use that.

const filterByDateWhereClause = (startDate: moment$Moment, endDate: moment$Moment): string => {...};

I wouldn't recommend the global usage though since it's less explicit where the type is coming from.

Holozoic answered 28/3, 2017 at 2:30 Comment(2)
The moment$Moment won't work for me, perhaps because I'm using Webpack so there's no global namespace? The two import methods worked.Thirtieth
Webpack shouldn't have an effect on how flow runs -- I'm not sure why the global type isn't working for you but it's fine because you shouldn't really use it... In the CONTRIBUTING.md doc for flow-typed, it tells libdef authors to prefix globals that aren't meant to be global: (github.com/flowtype/flow-typed/blob/…), so you shouldn't be using that anyway :)Holozoic
T
0

It seems as if creating a subclass from the moment object solves this problem:

import moment from 'moment';

class Moment extends moment {}

const filterByDateWhereClause = (startDate: Moment, endDate: Moment): string => {...};

Still interested to know if this the correct way to annotate a Moment.JS object however.

Thirtieth answered 27/3, 2017 at 1:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.