I have a generic interface defined as
export interface EventInput {
eventName: string;
metadata?: Record<string, string>;
payload?: Record<string, unknown>;
}
and I create a class
import {EventInput, EventUtilsService} from "@learnapp-co/la-event-utils";
import {UpdateOrganisationInterface} from "./interface";
export interface OrganisationUpdatedPayload {
orgId: string;
pii: string;
}
export class OrganisationUpdatedEventInput implements EventInput {
private readonly eventName = 'OrganisationUpdated';
private readonly payload: OrganisationUpdatedPayload;
constructor(orgId: string, body: UpdateOrganisationInterface, secret: string) {
this.payload = {
orgId,
pii: EventUtilsService.encryptPIIData({
organisationName: body.name,
bank: body.bank,
...(body.revenuePercentage && { revenuePercentage: body.revenuePercentage}),
}, secret),
}
}
public get getEventName(): string {
return this.eventName
}
public get getPayload(): OrganisationUpdatedPayload {
return this.payload
}
}
But I am getting the error
TS2416: Property 'payload' in type 'OrganisationUpdatedEventInput' is not assignable to
the same property in base type 'EventInput'. Type 'OrganisationUpdatedPayload' is not
assignable to type 'Record<string, unknown>'. Index signature is missing in type
'OrganisationUpdatedPayload'.
NOTE: - There can be as many classes as possible for eg OrganisationCreatedeventInput
with a different payload
which will extend EventInput
class.
How can we solve this issue?
CodePudding user response:
You're stating that OrganisationUpdatedEventInput
must implement EventInput
that has a payload
property with a broad type.
Then you declare a different (narrowed) type directly on OrganisationUpdatedEventInput
. This is not allowed as you can see in your error.
Typescript is telling you that you either need to narrow down the payload
property on EventInput
or allow this broader type in OrganisationUpdatedEventInput
.
I would suggest that you either use generics: interface EventInput<T>
as mentioned by @Yurii Panasenko:
Or use the broader type in OrganisationUpdatedEventInput
and narrow it down in the getter getPayload
with a safety check to make sure it's the correct type.
Also you're declaring properties in EventInput
interface as public (as interfaces do) and then declare them private in OrganisationUpdatedEventInput
. This is also not supported by TypeScript and doesn't really make sense.
If you want to do things this way, it may be better to just use inheritance. Make a base class EventInput
and extend OrganisationUpdatedEventInput
from this class. Something like this:
export abstract class EventInput<T> {
protected abstract readonly eventName: string;
protected readonly payload?: T;
protected metadata?: Record<string, string>;
constructor(payLoad?: T) {
this.payload = payLoad;
}
}
export interface OrganisationUpdatedPayload {
orgId: string;
pii: string;
}
export class OrganisationUpdatedEventInput extends EventInput<OrganisationUpdatedPayload> {
protected readonly eventName = 'OrganisationUpdated';
constructor(orgId: string, pii: string) {
super({ orgId, pii });
}
public get getEventName(): string {
return this.eventName;
}
public get getPayload(): OrganisationUpdatedPayload | undefined {
return this.payload;
}
}
CodePudding user response:
You can try to use T parameter
export interface EventInput<T> {
eventName: string;
metadata?: Record<string, string>;
payload?: T;
}
export class OrganisationUpdatedEventInput implements EventInput<OrganisationUpdatedPayload> {
private readonly eventName = 'OrganisationUpdated';
private readonly payload: OrganisationUpdatedPayload;
constructor(orgId: string, body: UpdateOrganisationInterface, secret: string) {
this.payload = {
orgId,
pii: EventUtilsService.encryptPIIData({
organisationName: body.name,
bank: body.bank,
...(body.revenuePercentage && { revenuePercentage: body.revenuePercentage}),
}, secret),
}
}
public get getEventName(): string {
return this.eventName
}
public get getPayload(): OrganisationUpdatedPayload {
return this.payload
}
}