Skip to content

Feathers Typescript - Typed HookContext #1952

Description

@EmirGluhbegovic

Steps to reproduce

There is an issue titled similar to mine, but it drifts to typing the sequelize models.

My goals:

  • Be able to do app.get([typed options appear here])
  • Be able to do app.service([typed options appear here]) -> this does not happen when using HookContext

In my attempt to solve this I tried the following:

in the declarations.d.ts file:

imports....
  import config from '@config/default.json';
 declarations...

// A mapping of service names to types. Will be extended in service files.
export interface EntityServices {
	users: Service<UserInterface>;
	subscribers: Service<SubscriberInterface>;
	permissions: Service<PermissionInterface>;
}

type Config = typeof config;

interface ModifiedConfig extends Config {
	sequelizeClient: Sequelize.Sequelize;
	'view engine': 'ejs';
}

export interface ServiceTypes extends EntityServices {}

type initialApplication = ExpressFeathers<ServiceTypes>;

type AppGet = <T extends keyof ModifiedConfig>(path: T) => ModifiedConfig[T];
type AppSet = <T extends keyof ModifiedConfig>(
	path: T,
	config: ModifiedConfig[T],
) => initialApplication;

// The application instance type that will be used everywhere else
export interface Application extends Omit<initialApplication, 'get' | 'set'> {
	get: AppGet;
	set: AppSet;
}

export type Paths = keyof ServiceTypes;
export type EntityPaths = keyof EntityServices;

export interface APIHookContext extends FeathersHookContext {
	app: Application;
	path: Paths;
}

export interface HookContext extends FeathersHookContext {}

This initially works perfectly but the issue comes in the use:

In a hook function if I change:

This:

export const sendNewUserEmail = async (context: HookContext) => { [some code...] return context; };

To this:

export const sendNewUserEmail = async (context: APIHookContext) => { [some code...] return context; };

I get all of typing BUT, all hell breaks loose with some of the following:

The service.hooks(hooks); call, now complains of a mismatch between the application and paths object of APIHookContext and HookContext.

On deeper inspection I see within the feathers typing, HookContext refers to "this", which I believe is the uninitialized application. Hence my object is populated while "this" is empty.

I tried further by extracting the service.hooks() function and updating its type but then the issue arises with feathers imports such as "feathers-hooks-common" functions. They pass HookContext which then does not match with APIHookContext.

A sample of the type error on the service.hooks function:

...type '(((context: HookContext<any, Service<any>>) => Promise<HookContext<any, Service<any>>>) | ((context: APIHookContext) => Promise<...>))[]' is not assignable to type 'Hook<any, Service<any>>[]'. Type '((context: HookContext<any, Service<any>>) => Promise<HookContext<any, Service<any>>>) | ((context: APIHookContext) => Promise<...>)' is not assignable to type 'Hook<any, Service<any>>'. Type '(context: APIHookContext) => Promise<APIHookContext>' is not assignable to type 'Hook<any, Service<any>>'. Types of parameters 'context' and 'hook' are incompatible. Type 'HookContext<any, Service<any>>' is not assignable to type 'APIHookContext'. Types of property 'app' are incompatible. Type 'Application<{}>' is missing the following properties from type 'Application': request, response, init, defaultConfiguration, and 40 more.ts(2345)

I would like to have a consistent application object that is used inside hook methods, class methods etc... that has all of the services and their types and things such as a typed get object etc...

I have been able to achieve this in the declaration.d.ts file but the above conflicts and the reference to "this" are blocking me.

Let me know what is possible and if there is a way to achieve this level of typing.

Regards

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions