Skip to content

Instantly share code, notes, and snippets.

@svallory
Created January 25, 2023 21:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save svallory/59cf4fb527ffeedb5fc03fbd388aac7c to your computer and use it in GitHub Desktop.
Save svallory/59cf4fb527ffeedb5fc03fbd388aac7c to your computer and use it in GitHub Desktop.
Magic catch-all method in Typescript class by extending Javascript Proxy class to build the perfect Value Object base class
type Setters<Type> = {
[Property in keyof Type as `set${Capitalize<string & Property>}`]: (newValue: Type[Property]) => Type & Setters<Type>
};
abstract class VO<T> {
constructor(
public readonly type: any,
public readonly excludedProperties: string[],
) {
return (new Proxy(this, {
apply: (target, thisArg, argArray) => {
if (!thisArg.hasOwnProperty(target)) {
throw new Error(`Method ${target} is not defined on ${thisArg}`);
}
return thisArg[target](...argArray);
}
}) as unknown as VO<T> & Setters<T>);
}
}
class InviteeVO extends VO<InviteeVO> {
constructor(
public readonly name: string,
public readonly email: string,
public readonly invite: number,
) {
super(Invitee, ['name', 'status', 'invite']);
return (this as unknown as InviteeVO & Setters<InviteeVO>);
}
}
type InviteeSetters = Setters<InviteeVO>;
export const Invitee: typeof InviteeVO & InviteeSetters = InviteeVO as any;
const john = new InviteeVO('John Snow', 'contact@starkfamily.com', 1) as InviteeVO & InviteeSetters;
const arya = john.setName('Arya Stark').setInvite(2);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment