Skip to content

Instantly share code, notes, and snippets.

@jack-guy
Last active September 7, 2017 10:34
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jack-guy/9d4ed79118e2656f5e3d2d699296ed36 to your computer and use it in GitHub Desktop.
Save jack-guy/9d4ed79118e2656f5e3d2d699296ed36 to your computer and use it in GitHub Desktop.
These are basic typings for Feathers.js based off of those in DefinitelyTyped for Express. This doesn't type feathers plugins, but does have some interfaces that can be used in them. WIP.
// Type definitions for Feathers
// Project: http://feathersjs.com/
// Definitions by: Jack Guy <http://thatguyjackguy.com>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
import { Application, Handler, ErrorRequestHandler } from 'express';
type HandlerArgument = Handler | Handler[];
export = Feathers;
declare function Feathers(): Feathers.FeathersApp;
declare namespace Feathers {
// The app object returned from the feathers() constructor. Based on an Express app.
export interface FeathersApp extends Application {
// The version of Feathers from package.json
version: string;
methods: ['find', 'get', 'create', 'update', 'patch', 'remove'];
services: any;
providers: any[];
// Since configure was removed from Express
configure(Function): this;
service(location: string): service.FeathersServiceInstance<any>;
// Mixture of Express and Feathers - we have to duplicate these because there's no way
// in TypeScript to "override" an extends. So we rewrite them all, express included.
use(location: string, service: service.FeathersServiceConfig): this; // Feathers
use(...handlers: HandlerArgument[]): this; // Express
use(mountPoint: string | RegExp | (string | RegExp)[], ...handlers: HandlerArgument[]): this; // Express
use(errorHandler: ErrorRequestHandler);
setup(app: FeathersApp);
}
// Expose these to users for typings their hook creations
export type Hooks = hooks.FeathersHooks;
export type Hook<Resource> = hooks.FeathersHook<Resource>;
}
// Contains the typings for service-related features
declare namespace service {
// The Events that can be subscribed to
type FeathersEvent = 'create' | 'update' | 'patch' | 'remove';
// Shared methods between a FeathersService and it's instance
interface FeathersServiceMethods<Resource> {
find?(params: FeathersParams, callback?: Function): PromiseLike<FeathersPage<Resource>>;
get?(id: any, params: FeathersParams, callback?: Function): PromiseLike<Resource>;
create?(data: Resource, params: FeathersParams, callback?: Function): PromiseLike<Resource>;
update?(id: any, data: Resource, params: FeathersParams, callback?: Function): PromiseLike<Resource>;
patch?(id: any, data: Resource, params: FeathersParams, callback?: Function): PromiseLike<Resource>;
remove?(id: any, params: FeathersParams, callback?: Function): PromiseLike<Resource>;
}
// The returned / retrievable feathers.service (e.g. app.service('/users'))
interface FeathersServiceInstance<Resource> extends FeathersServiceMethods<Resource> {
before(hooks: hooks.FeathersHooks);
after(hooks: hooks.FeathersHooks);
on(event: FeathersEvent, callback: { (Resource): any });
}
// The interface that a new service object would implement
interface FeathersService<Resource> extends FeathersServiceMethods<Resource> {
(FeathersServiceConfig): FeathersServiceInstance<Resource>;
setup?(app: Feathers.FeathersApp, path?: string)
}
// Change pagination for a 'find' service call
interface FeathersFindConfig {
paginate?: {
default?: number;
max?: number;
} | boolean;
}
// Customize the creation of a feathers service
interface FeathersServiceConfig extends FeathersFindConfig {
before?: hooks.FeathersHooks;
after?: hooks.FeathersHooks;
}
// The parameters used by feathers services
interface FeathersParams {
query: any;
data: any;
result: any;
}
// Paginated resources returned by find
interface FeathersPage<Resource> {
total: number;
limit: number;
skip: number;
data: Resource[];
}
}
// Contains the typings for hook-related features
declare namespace hooks {
// The typings for the "hook" parameter in hook functions
interface FeathersHookInputBase {
method: string;
type: 'before' | 'after';
callback: Function;
params: any;
data: any;
app: Feathers.FeathersApp;
}
// We have an individual parameter typing for each hook type
interface FeathersHookInputGet extends FeathersHookInputBase { id: any; }
interface FeathersHookInputFind extends FeathersHookInputBase { }
interface FeathersHookInputCreate extends FeathersHookInputBase { data: any; }
interface FeathersHookInputUpdate extends FeathersHookInputBase { data: any; id: any; }
interface FeathersHookInputPatch extends FeathersHookInputBase { data: any; id: any; }
interface FeathersHookInputRemove extends FeathersHookInputBase { data: any; id: any; }
type FeathersHookInputAll =
FeathersHookInputGet | FeathersHookInputFind | FeathersHookInputCreate |
FeathersHookInputUpdate | FeathersHookInputPatch | FeathersHookInputRemove;
// The type of an actual hook function
interface FeathersHook<Input> {
(hook: Input): PromiseLike<any> | void
}
// Either an array of hooks or a single hook -
// so we don't have to rewrite a super complicated type each time
type FeatherHookArrayOrHook<Input> = Array<FeathersHook<Input>> | FeathersHook<Input>;
interface FeathersHooks {
all?: FeatherHookArrayOrHook<FeathersHookInputAll>;
find?: FeatherHookArrayOrHook<FeathersHookInputFind>;
get?: FeatherHookArrayOrHook<FeathersHookInputGet>;
create?: FeatherHookArrayOrHook<FeathersHookInputCreate>;
update?: FeatherHookArrayOrHook<FeathersHookInputUpdate>;
patch?: FeatherHookArrayOrHook<FeathersHookInputPatch>;
remove?: FeatherHookArrayOrHook<FeathersHookInputRemove>;
}
}
@JoshuaToenyes
Copy link

Thank you!

@zender
Copy link

zender commented Nov 22, 2016

Great work!

@thebarndog
Copy link

thebarndog commented Dec 8, 2016

Don't you have to wrap this in declare module "feathers" { ...}? I couldn't get this file to work as is. Had to tinker with it a bit to get completion and everything compiling. My final results are here.

Something to keep in mind too:

I'm guessing feathers was compiled by Babel? There's a known issue with using export default that causes feathers.default (in the compiled js) to be undefined. That means you have to use export = Feathers which then requires an import via import feathers = require('feathers'); or import * as feathers from feathers. That one took me a while to figure out.

@Chrisdf
Copy link

Chrisdf commented Jan 17, 2017

Does anyone have an example on how this type definition can be used? I am trying to implement it and finding it to be somewhat difficult

@jack-guy
Copy link
Author

@Chrisdf I copy it into an index.d.ts file in a custom_typings folder and then npm link it into @types/feathers. Works like a charm. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment