Skip to content

Instantly share code, notes, and snippets.

@nopeless
Created March 23, 2026 09:27
Show Gist options
  • Select an option

  • Save nopeless/9d29c657695fe859094aa0d84165851c to your computer and use it in GitHub Desktop.

Select an option

Save nopeless/9d29c657695fe859094aa0d84165851c to your computer and use it in GitHub Desktop.
interesting ts pattern i tried
class Car {
constructor(
public make: string,
public model: string,
) {}
}
const gasParent = {
gas: 0,
};
const refuelParent = {
refuel(this: Car & { gas: number }, amount: number) {
this.gas += amount;
console.log(`Refueled ${amount} units of gas for ${this.model}. Total gas: ${this.gas}`);
},
};
type Composers<This, Arr extends readonly unknown[]> = Arr extends readonly [
infer First,
...infer Rest,
]
? [
{
[K in keyof First]: First[K] extends (...args: infer As) => infer R
? (this: This & First, ...args: As) => R
: First[K];
},
...Composers<This & First, Rest>,
]
: Arr;
type Composed<Arr extends readonly unknown[], Acc> = Arr extends readonly [
infer First,
...infer Rest,
]
? Composed<Rest, Acc & First>
: Acc;
function Compose<Args extends unknown[], T extends {}, Parents extends readonly unknown[]>(
base: new (...args: Args) => T,
parents: Composers<T, Parents>,
) {
const clazz = class extends base {};
for (const parent of parents) {
Object.assign(clazz.prototype, parent);
}
return clazz as new (...args: Args) => T & Composed<Parents, {}>;
}
const ComposedCar = Compose(Car, [gasParent, refuelParent]);
const myCar = new ComposedCar("toyota", "corolla");
myCar.refuel(10);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment