I'm trying to write a flow interface file for url-pattern.
This is how the module is used:
import UrlPattern from 'url-pattern';
var pattern = new UrlPattern('...');
Here's what I have in my interface file so far:
type UrlPatternOptions = { ... }
declare class UrlPattern {
constructor(routePattern: string, options?: UrlPatternOptions): void;
match(pathname: string): ?Object;
stringify(params: Object): string;
}
declare module 'url-pattern' {
}
I can't seem to get that class to type check at all. I can do this to force it to recognize Pattern as the class UrlPattern, but then I get the error "Constructor cannot be called on UrlPattern".
import urlPattern from 'url-pattern';
var Pattern = (urlPattern: UrlPattern);
var pattern = new Pattern('...');
declare class UrlPattern {
...
}
declare module 'url-pattern': UrlPattern;
or this:
declare class UrlPattern {
...
}
declare module 'url-pattern' {
*: UrlPattern;
};
You are close:
declare class UrlPattern {
...
}
declare module 'url-pattern': typeof UrlPattern;
When you declare a class, it's the type of the instances of the class. You need to use typeof to annotate a class type itself.
Oh, interesting. I'll give that a shot. Did I miss this in the docs or is it new?
This is in the docs, but it can be a little confusing.
Closing, turns out I needed to ignore the node_modules folder even though it didn't contain flow types. Not making a separate issue as it's already being worked on. Thanks @nmn and @samwgoldman for the help here and in Reactiflux#flow!
Borrowing this issue even if it's closed, hope you don't mind.
I am trying to do this accoring to what @nmn suggested:
declare class [Class] {
...
}
declare module [Module]: typeof [Class];
where Class and Module is the respective module / class names.
However, I am getting the error Library parse errorwith Unexpected token :
I have tried every syntax I could think of, but can't get flow to accept it as a module declaration.
So, is this the recommended way to tell flow that a module is also a class?
I see usages of typeof in the docs, but not with declarations.
I am using the npm package flow-bin if that makes any difference.
Turns out exports is a special word in a module declaration. Try this:
declare class ...
declare module [module] {
declare var exports: [class];
}
Works great!
Thanks a lot for the fast answer.
Just to update, after trying all these combinations, @spicydonuts's last comment was only partially right. Here is the code I want to type correctly:
var InlineStylePrefixer = require('inline-style-prefixer');
var getPrefixedStyle = function (
style: Object,
componentName: ?string,
userAgent?: ?string,
): Object {
var prefixer = new InlineStylePrefixer(userAgent);
return prefixer.prefix(style);
};
module.exports = {
getPrefixedStyle
};
And here is the definition file that worked:
declare class InlineStylePrefixer {
constructor(userAgent?: ?string): void;
prefix(style: Object): Object;
}
declare module 'inline-style-prefixer' {
declare var exports: typeof InlineStylePrefixer;
}
Almost the same as the last comment, with the addition of typeof.
It seems like the suggested approach here is a bit dangerous. The module's exported class is being declared in the global scope of your project. For example:
declarations.js:
declare class Thing {}
declare module 'thing' {
declare var exports:typeof Thing;
}
source.js:
// Note intentional typo!
import Thng from 'thing';
const stuff = new Thing(); // This should be an error, but it isn't!
I think a better pattern is to scope the class, and maybe prefix it to be clear that it's not a real export:
declarations.js:
declare module 'thing' {
declare class _Thing {}
declare var exports:typeof _Thing;
}
@nevir I agree, that's why you see hacky namespacing like this in flow-typed definitions:
declare class moment$Moment {
...
}
declare module "moment" {
declare var exports: Class<moment$Moment>;
}
Most helpful comment
It seems like the suggested approach here is a bit dangerous. The module's exported class is being declared in the global scope of your project. For example:
declarations.js:source.js:I think a better pattern is to scope the class, and maybe prefix it to be clear that it's not a real export:
declarations.js: