Skip to content

Instantly share code, notes, and snippets.

@hasparus
Last active August 19, 2019 12:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hasparus/da3987e74ee90f0684a04aec4053d4b1 to your computer and use it in GitHub Desktop.
Save hasparus/da3987e74ee90f0684a04aec4053d4b1 to your computer and use it in GitHub Desktop.
type Fluent<T extends object> = {
[K in keyof T]: (() => void) extends T[K]
? T[K] extends (...args: infer Params) => void
? (...args: Params) => Fluent<T>
: T[K]
: T[K];
};
/**
* It will behave in a weird way if we have methods that sometimes return and sometimes don't.
* We're fine with it, because we're using proper error handling techniques.
*/
function fluent<C extends new(...args: any[]) => any>(klass: C): (...args: ConstructorParameters<C>) => Fluent<InstanceType<C>> {
const prototype = Object.fromEntries(
Object.entries(klass.prototype).map(([k, v]) => {
if (typeof v !== 'function') {
return [k, v];
}
return [
k,
// eslint-disable-next-line func-names
function(this: InstanceType<C>, ...args: unknown[]) {
const res = v.apply(this, args);
if (res === undefined) {
return this;
}
return res;
},
];
})
) as any;
function ctor(...args: ConstructorParameters<C>): Fluent<InstanceType<C>> {
const self = new klass(...args);
Object.setPrototypeOf(self, prototype);
return self as Fluent<InstanceType<C>>;
}
return ctor;
}
const searchParams = fluent(URLSearchParams)
console.log(
searchParams(window.location.search).set("a", "0010").set("b", "202222").delete("a").set("c", "30").toString()
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment