Last active
May 7, 2022 13:20
-
-
Save jfet97/9b5d4d9c0b1d94ac0b5648d120333f0b to your computer and use it in GitHub Desktop.
Solution to https://github.com/typescript-exercises/typescript-exercises/tree/master/src/exercises/6
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
/* | |
Intro: | |
Filtering requirements have grown. We need to be | |
able to filter any kind of Persons. | |
Exercise: | |
Fix typing for the filterPersons so that it can filter users | |
and return User[] when personType='user' and return Admin[] | |
when personType='admin'. Also filterPersons should accept | |
partial User/Admin type according to the personType. | |
`criteria` argument should behave according to the | |
`personType` argument value. `type` field is not allowed in | |
the `criteria` field. | |
Higher difficulty bonus exercise: | |
Implement a function `getObjectKeys()` which returns more | |
convenient result for any argument given, so that you don't | |
need to cast it. | |
let criteriaKeys = Object.keys(criteria) as (keyof User)[]; | |
--> | |
let criteriaKeys = getObjectKeys(criteria); | |
*/ | |
interface User { | |
type: "user"; | |
name: string; | |
age: number; | |
occupation: string; | |
} | |
interface Admin { | |
type: "admin"; | |
name: string; | |
age: number; | |
role: string; | |
} | |
export type Person = User | Admin; | |
export const persons: Person[] = [ | |
{ | |
type: "user", | |
name: "Max Mustermann", | |
age: 25, | |
occupation: "Chimney sweep", | |
}, | |
{ type: "admin", name: "Jane Doe", age: 32, role: "Administrator" }, | |
{ type: "user", name: "Kate Müller", age: 23, occupation: "Astronaut" }, | |
{ type: "admin", name: "Bruce Willis", age: 64, role: "World saver" }, | |
{ type: "user", name: "Wilson", age: 23, occupation: "Ball" }, | |
{ type: "admin", name: "Agent Smith", age: 23, role: "Anti-virus engineer" }, | |
]; | |
export function logPerson(person: Person) { | |
console.log( | |
` - ${person.name}, ${person.age}, ${ | |
person.type === "admin" ? person.role : person.occupation | |
}` | |
); | |
} | |
const getObjectKeys = <T extends object>(obj: T) => | |
Object.keys(obj) as (keyof T)[]; | |
function isPersonType<K extends Person["type"]>(personType: K) { | |
return (person: Person): person is Extract<Person, { type: K }> => | |
person.type === personType; | |
} | |
export function filterPersons<T extends Person["type"]>( | |
persons: Person[], | |
personType: T, | |
criteria: Partial<Omit<Extract<Person, { type: T }>, "type">> | |
): Extract<Person, { type: T }>[] { | |
return persons | |
// la lambda in input alla filter deve essere una type guard | |
.filter(isPersonType(personType)) | |
.filter((person) => | |
// criteria potrebbe avere prop estranee a Person => il check fallisce | |
getObjectKeys(criteria).every( | |
(fieldName) => person[fieldName] === criteria[fieldName] | |
) | |
); | |
} | |
export const usersOfAge23 = filterPersons(persons, "user", { age: 23 }); | |
export const adminsOfAge23 = filterPersons(persons, "admin", { age: 23 }); | |
export const usersadminsOfAge23 = filterPersons(persons, Math.random() > 0.5 ? "admin" : "user", { age: 23 }); | |
console.log("Users of age 23:"); | |
usersOfAge23.forEach(logPerson); | |
console.log(); | |
console.log("Admins of age 23:"); | |
adminsOfAge23.forEach(logPerson); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment