Skip to content

Support for typed "this" in lifecycle methods (created, started, stopped) #70

@marceliwac

Description

@marceliwac

Hi, at the moment it seems like there is no way to override the type for this parameter for the lifecycle methods (created , started and stopped). In consequence, it's impossible to create those methods if they implement a custom this (similarly to how methods and actions do it).

This can be temporarily ignored as suggested in #67, but that's a workaround and not a fix.

I'm realtively new to typescript so I might be missing some obvious solution / best practices related to this, but I think the following could work:

index.d.ts

// ...

type ServiceSyncLifecycleHandler<S = ServiceSettingSchema> = (this: Service<S>) => void;
type ServiceAsyncLifecycleHandler<S = ServiceSettingSchema> = (this: Service<S>) => void | Promise<void>;

interface ServiceSchema<S = ServiceSettingSchema> {
	name: string;
	version?: string | number;
	settings?: S;
	dependencies?: string | ServiceDependency | (string | ServiceDependency)[];
	metadata?: any;
	actions?: ServiceActionsSchema;
	mixins?: Partial<ServiceSchema>[];
	methods?: ServiceMethods;
	hooks?: ServiceHooks;

	events?: ServiceEvents;
	created?: ServiceSyncLifecycleHandler<S> | ServiceSyncLifecycleHandler<S>[];
	started?: ServiceAsyncLifecycleHandler<S> | ServiceAsyncLifecycleHandler<S>[];
	stopped?: ServiceAsyncLifecycleHandler<S> | ServiceAsyncLifecycleHandler<S>[];

	[name: string]: any;
}

// ...

should be changed to:

index.d.ts

// ...

type ServiceSyncLifecycleHandler<S = ServiceSettingsSchema, T = Service<S>> = (this: T) => void;
type ServiceAsyncLifecycleHandler<S = ServiceSettingSchema, T = Service<S>> = (this: T) => void | Promise<void>;


interface ServiceSchema<S = ServiceSettingSchema, T = void> {
	name: string;
	version?: string | number;
	settings?: S;
	dependencies?: string | ServiceDependency | (string | ServiceDependency)[];
	metadata?: any;
	actions?: ServiceActionsSchema;
	mixins?: Partial<ServiceSchema>[];
	methods?: ServiceMethods;
	hooks?: ServiceHooks;

	events?: ServiceEvents;
	created?: ServiceSyncLifecycleHandler<S, T> | ServiceSyncLifecycleHandler<S, T>[];
	started?: ServiceAsyncLifecycleHandler<S, T> | ServiceAsyncLifecycleHandler<S, T>[];
	stopped?: ServiceAsyncLifecycleHandler<S, T> | ServiceAsyncLifecycleHandler<S, T>[];

	[name: string]: any;
}

// ...

The above code is meant to provide a way to supply additional type for this parameter at the service declaration level (e.g. in greeter.service.ts), which would change it from:

export interface GreeterSettings extends ServiceSettingSchema {
	defaultName: string;
}

export interface GreeterMethods {
	uppercase(str: string): string;
}

export type GreeterThis = Service<GreeterSettings> & GreeterMethods;

const GreeterService: ServiceSchema<GreeterSettings> = {
	name: "greeter",
	settings: {
		defaultName: "Moleculer",
	},
	dependencies: [],
	actions: {},
	events: {},
	methods: {
		uppercase(str: string) {
			return str.toUpperCase()();
                 },
	},
	created(this: GreeterThis) {	 		//  <--  This does not work
		console.log(this.broker.services);
	},

	async started(this: GreeterThis){ 	 	//  <--  This does not work
		this.uppercase('hello world');
	},

	async started(this: GreeterThis){  		//  <--  This does not work
		this.uppercase('goodbye world');
	},
};

to

export interface GreeterSettings extends ServiceSettingSchema {
	defaultName: string;
}

export interface GreeterMethods {
	uppercase(str: string): string;
}

export type GreeterThis = Service<GreeterSettings> & GreeterMethods;

const GreeterService: ServiceSchema<GreeterSettings, GreeterThis> = {	//  <--  This is the actual change
									//       in service declaration
	name: "greeter",
	settings: {
		defaultName: "Moleculer",
	},
	dependencies: [],
	actions: {},
	events: {},
	methods: {
		uppercase(str: string) {
			return str.toUpperCase()();
                 },
	},
	created(this: GreeterThis) {
		console.log(this.broker.services);
	},

	async started(this: GreeterThis){
		this.uppercase('hello world');
	},

	async started(this: GreeterThis){
		this.uppercase('goodbye world');
	},
};

Please let me know if you'd like me to create a PR with this change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions