Created
January 26, 2022 20:35
-
-
Save PanagiotisPtr/14ee4da458273cfda769a7b74be27c59 to your computer and use it in GitHub Desktop.
Solution to exercise 4.b from Chapter 5 of "Programming TypeScript"
This file contains 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
/** | |
* Create a class that uses the builder pattern and only allows the 'send' method to be called only | |
* when both setUrl and setMethod have been called before it (in any order) | |
*/ | |
interface WithUrl { | |
getUrl(): string; | |
setMethod(method: string): ReadyToSend; | |
} | |
interface WithMethod { | |
getMethod(): string; | |
setUrl(url: string): ReadyToSend; | |
} | |
interface ReadyToSend extends WithUrl, WithMethod { | |
send(): void; | |
} | |
type ClassConstructor<T = any> = { | |
new(...args: any[]): T | |
} | |
const WithUrl = < | |
T extends ClassConstructor | |
>(Class: T, url: string) => { | |
return class extends Class implements WithUrl { | |
getUrl(): string { | |
return url; | |
} | |
setMethod(method: string): ReadyToSend { | |
const BuilderWithMethod = WithMethod( | |
Object.getPrototypeOf(this).constructor, | |
method | |
); | |
const FinalBuilder = WithMethodAndUrl( | |
BuilderWithMethod | |
); | |
return new FinalBuilder(); | |
} | |
} | |
} | |
const WithMethod = < | |
T extends ClassConstructor | |
>(Class: T, method: string) => { | |
return class extends Class implements WithMethod { | |
getMethod(): string { | |
return method; | |
} | |
setUrl(url: string): ReadyToSend { | |
const BuilderWithUrl = WithUrl( | |
Object.getPrototypeOf(this).constructor, | |
url | |
); | |
const FinalBuilder = WithMethodAndUrl( | |
BuilderWithUrl | |
); | |
return new FinalBuilder(); | |
} | |
} | |
} | |
const WithMethodAndUrl = < | |
T extends ClassConstructor<WithUrl & WithMethod> | |
>(Class: T) => { | |
return class extends Class implements ReadyToSend { | |
send(): void { | |
console.log(this.getUrl(), this.getMethod()); | |
} | |
} | |
} | |
class Builder { | |
setUrl(url: string): WithUrl { | |
const BuilderWithUrl = WithUrl(Builder, url); | |
return new BuilderWithUrl(); | |
} | |
setMethod(method: string): WithMethod { | |
const BuilderWithUrl = WithMethod(Builder, method); | |
return new BuilderWithUrl(); | |
} | |
} | |
let a = new Builder(); | |
a.setUrl('someUrl').setMethod('someMethod').send(); | |
let b = new Builder(); | |
b.setMethod('someOtherMethod').setUrl('someOtherUrl').send(); | |
let c = new Builder(); | |
// c.setUrl('url').send(); // error | |
// c.setMethod('method').send(); // error |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment