ts-class-mixing
Version:
Composable mixin utility for TypeScript with full type inference and runtime detection
96 lines (76 loc) • 2.06 kB
text/typescript
import { Mixin } from "../src/Mixin";
import { assert, test, describe } from "vitest";
class CanAttack {
attack(target: Actor, damage: number = 0) {
target.hp -= damage;
return "attacks!";
}
}
class CanCastSpells {
cast() {
return "casts a spell!";
}
}
class CanCastSuperPower {
castSuperPower() {
return "casts a super power!";
}
}
class Actor extends CanAttack {
hp: number = 0;
act() {
return "moves silently";
}
}
class Hero extends Mixin([Actor, CanCastSpells, CanCastSuperPower]) {
hp = 100;
name = "Hero";
}
class Enemy extends Actor {
type = "Generic Enemy";
isEnemy(target: any) {
return target.isOfType?.(Hero) || target instanceof Hero;
}
findEnemy(targets: any[]) {
return targets.find((target) => this.isEnemy(target));
}
}
class Goblin extends Mixin([Enemy]) {
constructor(public hp: number) {
super();
}
laugh() {
return "goblin laughs";
}
}
class GoblinBoss extends Mixin([Goblin, CanCastSpells]) {
constructor(public hp: number) {
super();
}
taunt() {
return "Goblin Boss taunts!";
}
}
describe("Mixin", () => {
test("should work", () => {
const goblin = new Goblin(10);
const boss = new GoblinBoss(50);
const hero = new Hero();
assert.strictEqual(hero.attack(goblin), "attacks!");
assert.strictEqual(hero.cast(), "casts a spell!");
assert.strictEqual(hero.castSuperPower(), "casts a super power!");
assert.strictEqual(goblin.act(), "moves silently");
assert.strictEqual(goblin.attack(hero), "attacks!");
assert.strictEqual(boss.taunt(), "Goblin Boss taunts!");
assert.strictEqual(boss.cast(), "casts a spell!");
assert.instanceOf(boss.findEnemy([goblin, hero]), Hero);
assert.isTrue(hero.isOfType(CanCastSpells));
assert.isTrue(goblin.isOfType(Actor));
assert.isTrue(boss.isOfType(Enemy));
assert.strictEqual(hero.hp, 100);
assert.strictEqual(boss.hp, 50);
assert.strictEqual(goblin.hp, 10);
hero.attack(boss, 10);
assert.strictEqual(boss.hp, 40);
});
});