Last active
May 12, 2022 21:39
-
-
Save steveruizok/bd856d90e2635ccb1892e13cbfa8d18d to your computer and use it in GitHub Desktop.
Stupidly complex TypeScript class solution
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Model<T> = { | |
[E in keyof T]: unknown; | |
} | |
export type DefaultModel = { | |
[k: string]: unknown; | |
}; | |
class View<E extends Model<E> = Model<unknown>> { | |
model: E; | |
constructor(model: E) { | |
this.model = model; | |
} | |
update = <T extends E>(partialModel: Partial<T>) => { | |
Object.assign(this.model, partialModel); | |
}; | |
} | |
// A | |
type ShipModel<T> = { | |
type: "ship"; | |
} & Model<T>; | |
class ShipView<E extends ShipModel<E> = ShipModel<unknown>> extends View<E> { | |
static type = 'ship' as const | |
} | |
const shipA = new ShipView({ | |
type: "ship" | |
}); | |
shipA.update({ type: 'ship' }) | |
// @ts-expect-error | |
shipA.update({ cat: 4 }) // No cat property on shipA! | |
const shipB = new ShipView({ | |
type: "ship", | |
cat: 4 | |
}); | |
shipB.update({ cat: 4 }) // ok here | |
// B | |
type BoatModel<T> = { | |
type: "boat"; | |
} & Model<T>; | |
class BoatView<E extends BoatModel<E> = BoatModel<unknown>> extends View<E> { | |
static type = 'boat' as const | |
} | |
const boat = new BoatView({ | |
type: "boat", | |
}); | |
// Instances... | |
type Views = ShipView | BoatView | |
const views: Views[] = [ | |
shipA, | |
shipB, | |
boat, | |
] | |
// And their constructors... | |
interface ViewConstructor<A extends View> { | |
new(...args: A extends new (...args: infer U) => any ? U : never): A; | |
type: A["model"] extends { type: any } ? A["model"]["type"] : never; | |
} | |
const example: ViewConstructor<ShipView> = ShipView | |
const ViewCtors: ViewConstructor<Views>[] = [ | |
ShipView, BoatView, | |
] | |
type A = ViewConstructor<ShipView>["type"] // "ship" | |
type B = ViewConstructor<ShipView>["type"] // "ship" | |
type C = ViewConstructor<BoatView>["type"] // "boat" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment