Skip to content

Instantly share code, notes, and snippets.

@hasparus
Created June 9, 2019 10:36
Show Gist options
  • Save hasparus/fa84cab775d4a26994b785fb27322f7d to your computer and use it in GitHub Desktop.
Save hasparus/fa84cab775d4a26994b785fb27322f7d to your computer and use it in GitHub Desktop.
type Primitive = string | number;
type Constructor<T, Args extends any[]> = {
new (...args: Args): T;
(...args: Args): T;
};
function makeConstructor<
T,
Args extends any[],
P extends Record<string, Primitive | ((this: T) => any)>
>(create: (...args: Args) => T, prototype?: P) {
const constructor = function(this: T | undefined, ...args: Args) {
if (this instanceof constructor) {
return Object.assign(this, create(...args));
}
return new constructor(...args);
} as Constructor<T & P, Args>;
constructor.prototype = prototype || {};
return constructor;
}
type CharacterStats = {
strength: number;
wisdom: number;
charisma: number;
};
const Character = makeConstructor(
(characterName: string, stats: CharacterStats) => ({
// instance
characterName,
stats,
level: 1,
}),
{
// prototype
__brand: "Character" as const,
sayHello() {
console.log(
"Hi, I'm",
this.characterName,
this.level,
this.stats,
// **challenge** how to type this without using `class`?
this.sayHello
);
},
}
);
type Character = ReturnType<typeof Character>;
const merlin = Character("Merlin", { charisma: 6, wisdom: 10, strength: 2 });
const kingArthur = new Character("King Arthur", {
charisma: 7,
strength: 9,
wisdom: 5,
});
merlin.sayHello();
kingArthur.sayHello();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment