Created
April 18, 2022 14:20
-
-
Save matthijsgroen/648126b8d790a99879cd0bc745c54df7 to your computer and use it in GitHub Desktop.
Function composition with 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
console.log("hello world"); | |
const data = { | |
projects: [ | |
{ technology: "Java", name: "Project1", budget: 1000, finishedInDays: 10 }, | |
{ technology: "Java", name: "Project1", budget: 2000, finishedInDays: 15 }, | |
{ technology: "Ruby", name: "Test", budget: 800, finishedInDays: 3 }, | |
{ technology: "Ruby", name: "Backend", budget: 1200, finishedInDays: 10 }, | |
{ technology: "Python", name: "Backend", budget: 1200, finishedInDays: 9 }, | |
{ | |
technology: "React", | |
name: "Expensive", | |
budget: 3800, | |
finishedInDays: 40, | |
}, | |
], | |
employees: [ | |
{ firstName: "Alice", lastName: "Cooper", age: 25 }, | |
{ firstName: "Bob", lastName: "Sinclair", age: 31 }, | |
{ firstName: "Claire", lastName: "Unknown", age: 52 }, | |
], | |
}; | |
const query = <DataCollection extends Record<string, any[]>>( | |
dataCollection: DataCollection | |
) => { | |
type Source = keyof DataCollection; | |
type FieldsOfType<Record extends {}, Type> = { | |
[R in keyof Record]: Record[R] extends Type ? R : never; | |
}[keyof Record]; | |
return { | |
from: <S extends Source>(source: S) => { | |
type RowType<List> = List extends Array<infer Item> ? Item : List; | |
type Row = RowType<DataCollection[S]>; | |
type Condition = (row: Row) => boolean; | |
type StringFields = FieldsOfType<Row, string>; | |
type NumberFields = FieldsOfType<Row, number>; | |
return { | |
where: (condition: Condition): Row[] => | |
dataCollection[source].filter<Row>((r): r is Row => condition(r)), | |
startsWith: | |
(field: StringFields, value: string): Condition => | |
(row) => | |
row[field].startsWith(value), | |
greaterThan: | |
(field: NumberFields, value: number): Condition => | |
(row) => | |
row[field] > value, | |
lessThan: | |
(field: NumberFields, value: number): Condition => | |
(row) => | |
row[field] < value, | |
or: | |
(a: Condition, b: Condition): Condition => | |
(r) => | |
a(r) || b(r), | |
and: | |
(a: Condition, b: Condition): Condition => | |
(r) => | |
a(r) && b(r), | |
}; | |
}, | |
}; | |
}; | |
const { where, and, greaterThan, startsWith } = query(data).from("employees"); | |
console.log(where(and(greaterThan("age", 20), startsWith("firstName", "Bo")))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment