Skip to content

Instantly share code, notes, and snippets.

@matthijsgroen
Created April 18, 2022 14:20
Show Gist options
  • Save matthijsgroen/648126b8d790a99879cd0bc745c54df7 to your computer and use it in GitHub Desktop.
Save matthijsgroen/648126b8d790a99879cd0bc745c54df7 to your computer and use it in GitHub Desktop.
Function composition with TypeScript
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