loading...

Advanced TypeScript Exercises - Answer 5

macsikora profile image Maciej Sikora Updated on ・2 min read

Advanced TypeScript Exercises (20 Part Series)

1) Advanced TypeScript Exercises - Question 1 2) Advanced TypeScript Exercises - Answer 1 3 ... 18 3) Advanced TypeScript Exercises - Question 2 4) Advanced TypeScript Exercises - Answer 2 5) Advanced TypeScript Exercises - Question 3 6) Advanced TypeScript Exercises - Answer 3 7) Advanced TypeScript Exercises - Question 4 8) Advanced TypeScript Exercises - Answer 4 9) Advanced TypeScript Exercises - Question 5 10) Advanced TypeScript Exercises - Answer 5 11) Advanced TypeScript Exercises - Question 6 12) Advanced TypeScript Exercises - Answer 6 13) Advanced TypeScript Exercises - Question 7 14) Advanced TypeScript Exercises - Answer 7 15) TypeScript Exercises Bonus🦠 - Type of Pandemia 16) TypeScript Exercises Bonus🦠 - Answers Part 1 17) TypeScript Exercises Bonus🦠 - Answers Part 2 18) Advanced TypeScript Exercises - Question 8 19) Advanced TypeScript Exercises - Answer 8 20) Advanced TypeScript Exercises - Question 9

1. Conditional types solution

type Config = {
  name: boolean;
  lastname: boolean;
};
type User = {
  name?: string;
  lastname?: string;
};

declare function getUser<
  C extends Config,
  _NamePart = C['name'] extends true ? Pick<Required<User>, 'name'> : {},
  _LastNamePart = C['lastname'] extends true ? Pick<Required<User>, 'lastname'> : {}
  >(
    config: C
): _NamePart & _LastNamePart;

Check the solution in the playground.

Explanation

  • declaration have generic type C extends Config in order to be able to work with narrowed variable type
  • we have created two local variables _NamePart and _LastNamePart, the purpose is readability
  • _NamePart = C['name'] extends true ? Pick<Required<User>, 'name'> : {} - if type variable C has name property set at true we assign type which has required field name from the original type User
  • _LastNamePart = C['lastname'] extends true ? Pick<Required<User>, 'lastname'> : {} - in the same way as before we ask about lastname
  • _NamePart & _LastNamePart we return intersection type, it means depends on what we get in particular parts we join those parts.

Take a look that I have used monoid property as in both conditional types I just fallback to {} as neutral element of & operation.

2. Overloads solution

type Config = {
  name: boolean;
  lastname: boolean;
};
type User = {
  name?: string;
  lastname?: string;
};

declare function getUser(
  config: { name: true; lastname: false}
): Pick<Required<User>,'name'>;

declare function getUser(
  config: { name: false; lastname: true}
): Pick<Required<User>,'lastname'>;

declare function getUser(
  config: { name: false; lastname: false}
): {};

declare function getUser(
  config: { name: true; lastname: true}
): Required<User>;

Check the solution in the playground

The solution with overloads is less sophisticated but also longer, in order to achieve the result we need to create overload for every possible correlation of both fields in Config, so exactly 4 versions.

  • Pick<Required<User>,'name'> we pick only name field from Userand say its required.
  • Required<User> - we say we get User but with all fields non-optional

Utility types used in both solutions:

  • Pick - allows for picking only wanted set of properties
  • Required - produce a type with all properties required

Also want to mention more sophisticated solution by Rahul Kashyap left in the comment - Solution from the comments section. Good job Rahul!

This series is will continue. If you want to know about new exciting questions from advanced TypeScript please follow me on dev.to and twitter.

Advanced TypeScript Exercises (20 Part Series)

1) Advanced TypeScript Exercises - Question 1 2) Advanced TypeScript Exercises - Answer 1 3 ... 18 3) Advanced TypeScript Exercises - Question 2 4) Advanced TypeScript Exercises - Answer 2 5) Advanced TypeScript Exercises - Question 3 6) Advanced TypeScript Exercises - Answer 3 7) Advanced TypeScript Exercises - Question 4 8) Advanced TypeScript Exercises - Answer 4 9) Advanced TypeScript Exercises - Question 5 10) Advanced TypeScript Exercises - Answer 5 11) Advanced TypeScript Exercises - Question 6 12) Advanced TypeScript Exercises - Answer 6 13) Advanced TypeScript Exercises - Question 7 14) Advanced TypeScript Exercises - Answer 7 15) TypeScript Exercises Bonus🦠 - Type of Pandemia 16) TypeScript Exercises Bonus🦠 - Answers Part 1 17) TypeScript Exercises Bonus🦠 - Answers Part 2 18) Advanced TypeScript Exercises - Question 8 19) Advanced TypeScript Exercises - Answer 8 20) Advanced TypeScript Exercises - Question 9

Posted on Mar 2 by:

macsikora profile

Maciej Sikora

@macsikora

I am Software Developer, currently interested in static type languages (TypeScript, Elm, Reason) mostly in the frontend land

Discussion

markdown guide