Created
June 23, 2018 23:13
-
-
Save frankpf/3d059543271a8c6a929bff757c4c4012 to your computer and use it in GitHub Desktop.
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
// Trying to simulate do-notation in TypeScript using async/await | |
// Trying to convert https://codewithstyle.info/advanced-functional-programming-typescript-monads-generators/ | |
// to use async/await. Generators work but aren't type safe because of https://github.com/Microsoft/TypeScript/issues/2983 | |
interface MyPromise<A> { | |
then<B>(fn: (a: A) => Option<B>): MyPromise<B> | |
} | |
export class Option<A> implements MyPromise<A> { | |
constructor(private readonly value: A | null) {} | |
static some<A>(value: A) { | |
return new Option<A>(value) | |
} | |
static none<A>() { | |
return new Option<A>(null) | |
} | |
static fromNullable<A>(value: A | null): Option<A> { | |
return value != null ? Option.some(value) : Option.none<A>() | |
} | |
map<B>(fn: (a: A) => B): Option<B> { | |
if (this.value == null) { | |
return Option.none() | |
} | |
return Option.some(fn(this.value)) | |
} | |
flatMap<B>(fn: (a: A) => Option<B>): Option<B> { | |
if (this.value == null) { | |
return Option.none() | |
} | |
return fn(this.value) | |
} | |
then = this.flatMap | |
} | |
class EmployeeRepository { | |
private employees: Employee[] = [ | |
{ id: 1, name: "John", supervisorId: Option.none() }, | |
{ id: 2, name: "Jane", supervisorId: Option.some(1) }, | |
{ id: 3, name: "Joe", supervisorId: Option.some(2) }, | |
]; | |
findById(id: number): Option<Employee> { | |
const results = this.employees.filter(employee => employee.id === id); | |
return results.length ? Option.some(results[0]) : Option.none(); | |
} | |
} | |
interface Employee { | |
id: number; | |
name: string; | |
supervisorId: Option<number>; | |
} | |
const repository = new EmployeeRepository() | |
function getSupervisorName1(maybeEnteredId: Option<string>): Option<string> { | |
return maybeEnteredId | |
.flatMap(employeeIdString => Option.fromNullable(parseInt(employeeIdString))) | |
.flatMap(employeeId => repository.findById(employeeId)) | |
.flatMap(employee => employee.supervisorId) | |
.flatMap(supervisorId => repository.findById(supervisorId)) | |
.map(supervisor => supervisor.name); | |
} | |
async function getSupervisorName2(maybeEnteredId: Option<string>): Promise<string> { | |
const enteredIdStr = await maybeEnteredId; | |
const enteredId = parseInt(enteredIdStr); | |
const employee = await repository.findById(enteredId); | |
const supervisorId = await employee.supervisorId; | |
const supervisor = await repository.findById(supervisorId); | |
return Option.some(supervisor.name); | |
} | |
async function main() { | |
const id = '3' | |
const r1 = getSupervisorName1(Option.some(id)) | |
console.log('r1: ', r1) | |
const r3 = await getSupervisorName2(Option.some(id)) | |
console.log('r3: ', r3) | |
} | |
main().then(() => console.log('Done!')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment