Last active
September 16, 2020 06:25
-
-
Save jLouzado/1a521481cafa36451d073e493230de6f to your computer and use it in GitHub Desktop.
Possible example for types-driven-development. Repl: https://www.typescriptlang.org/play
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
type EventsWithFilters = Record< | |
string, | |
{isSelected: boolean; filters: Filters} | |
> | null | |
type Filters = Record<string, {isSelected: boolean; values: Values}> | null | |
type Values = Record<string, boolean> | null | |
type SelectedFilters = { | |
event: string | |
filters: { | |
filter: string | |
values: string[] | |
}[] | |
}[] | |
/** | |
* Behaviour: | |
* return if `input` is null | |
* per `event`: | |
* - ignore if: | |
* - `filters` null | |
* - !selected | |
* - otherwise process `filters` | |
* per `filter`: | |
* - ignore if: | |
* - !selected | |
* - `values` null | |
* - otherwise process `values` | |
* per `value`: | |
* - is it selected | |
*/ | |
type Requirement = (input: EventsWithFilters) => SelectedFilters | null | |
const solution: Requirement = (input) => | |
input !== null | |
? Object.keys(input) | |
// transform from Object to Array | |
.map((event) => ({ | |
event, | |
filters: input[event].filters | |
})) | |
// filter out unselected filters and all the nested nulls | |
.map(removeAllNulls) | |
.map((val) => ({ | |
event: val.event, | |
filters: Object.keys(val.filters) | |
.map((f) => ({filter: f, values: val.filters[f]})) | |
// remove unselected values | |
.map(({filter, values}) => ({ | |
filter, | |
values: Object.keys(values).filter((v) => values[v]) | |
})) | |
})) | |
: null | |
/** in practice this would be several steps */ | |
declare const removeAllNulls: ( | |
x: {event: string; filters: Filters} | |
) => {event: string; filters: Record<string, NonNullable<Values>>} |
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
type EventsWithFilters = Record< | |
string, | |
{isSelected: boolean; filters: Filters} | |
> | null | |
type Filters = Record<string, {isSelected: boolean; values: Values}> | null | |
type Values = Record<string, boolean> | null | |
type SelectedFilters = { | |
event: string | |
filters: { | |
filter: string | |
values: string[] | |
}[] | |
}[] | |
/** | |
* Behaviour: | |
* return if `input` is null | |
* per `event`: | |
* - ignore if: | |
* - `filters` null | |
* - !selected | |
* - otherwise process `filters` | |
* per `filter`: | |
* - ignore if: | |
* - !selected | |
* - `values` null | |
* - otherwise process `values` | |
* per `value`: | |
* - is it selected | |
*/ | |
type Requirement = (input: EventsWithFilters) => SelectedFilters | null | |
const solution: Requirement = (input) => | |
input !== null | |
? Object.keys(input) | |
// transform from Object to Array | |
.map((event) => ({ | |
event, | |
filters: input[event].filters | |
})) | |
// remove filters that are null | |
.filter( | |
( | |
val | |
): val is { | |
event: string | |
filters: NonNullable<Filters> | |
} => val.filters !== null | |
) | |
// remove values that are null | |
.map((val) => ({ | |
event: val.event, | |
filters: Object.keys(val.filters).reduce( | |
( | |
acc: Record< | |
string, | |
{values: NonNullable<Values>; selected: boolean} | |
>, | |
f | |
) => { | |
const values = val.filters[f].values | |
return values === null | |
? acc | |
: { | |
...acc, | |
[f]: { | |
selected: val.filters[f].isSelected, | |
values | |
} | |
} | |
}, | |
{} | |
) | |
})) | |
// remove filters that are unselected | |
.map((val) => ({ | |
event: val.event, | |
filters: Object.keys(val.filters).reduce( | |
(acc: Record<string, NonNullable<Values>>, f) => { | |
const {selected, values} = val.filters[f] | |
return selected | |
? { | |
...acc, | |
[f]: values | |
} | |
: acc | |
}, | |
{} | |
) | |
})) | |
// final shape transformation | |
.map((val) => ({ | |
event: val.event, | |
filters: Object.keys(val.filters) | |
.map((f) => ({filter: f, values: val.filters[f]})) | |
// remove unselected values | |
.map(({filter, values}) => ({ | |
filter, | |
values: Object.keys(values).filter((v) => values[v]) | |
})) | |
})) | |
: null |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment