Skip to content

Instantly share code, notes, and snippets.

@siritori
Created July 9, 2016 01:25
Show Gist options
  • Save siritori/dee0f9617b597b2aa86ab6db5d4bbb65 to your computer and use it in GitHub Desktop.
Save siritori/dee0f9617b597b2aa86ab6db5d4bbb65 to your computer and use it in GitHub Desktop.
class PartialUpdate<Props>
{
constructor(protected props: Props) {
PartialUpdate.deepFreeze(this);
}
private static deepFreeze(o: any) {
Object.freeze(o);
var oIsFunction = typeof o === "function";
var hasOwnProp = Object.prototype.hasOwnProperty;
Object.getOwnPropertyNames(o).forEach(function (prop) {
if (hasOwnProp.call(o, prop)
&& (oIsFunction ? prop !== 'caller' && prop !== 'callee' && prop !== 'arguments' : true)
&& o[prop] !== null
&& (typeof o[prop] === "object" || typeof o[prop] === "function")
&& !Object.isFrozen(o[prop])) {
PartialUpdate.deepFreeze(o[prop]);
}
});
}
protected overwrite(partial_: Props): Props {
const partial = partial_ as any;
const prev = this.props as any;
return Object.getOwnPropertyNames(prev).reduce((acc, key) => {
acc[key] = partial.hasOwnProperty(key) ? partial[key] : prev[key];
return acc;
}, {} as any);
}
}
interface TestProps {
hoge?: number;
fuga?: string;
}
class Test extends PartialUpdate<TestProps> {
get hoge(): number {
return this.props.hoge;
}
get fuga(): string {
return this.props.fuga;
}
private update(props: TestProps): Test {
return new Test(this.overwrite(props));
}
public increment(): Test {
return this.update({ hoge: this.hoge + 1 });
}
public add(s: string): Test {
return this.update({fuga: this.fuga + s});
}
}
namespace TestFactory {
export function create() {
return new Test({
hoge: 0,
fuga: "",
});
}
}
// usage
const t1 = TestFactory.create();
const t2 = t1.increment().increment().add("a").add("b");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment