Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
marceliwac opened this issue Jan 30, 2024 · 2 comments

Comments

@marceliwac
Copy link

marceliwac commented Jan 30, 2024

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.

@marceliwac marceliwac changed the title Support for types for lifecycle methods (created, started, stopped) Support for typed "this" in lifecycle methods (created, started, stopped) Jan 30, 2024
@icebob
Copy link
Member

icebob commented Feb 3, 2024

Ok, plz create a PR and we can discuss your suggestion with other TS guys.

@marceliwac
Copy link
Author

@icebob I've just realised the type defs are in the other repository, I hope that's not a problem. It should now be cross-referenced.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants