How to specify a Moment.js object annotation in Flow

clhenrick picture clhenrick · Mar 27, 2017 · Viewed 7.3k times · Source

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?

Answer

Lewis Chung picture Lewis Chung · Mar 28, 2017

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.