Advanced TypeScript Exercises - Answer 5
Tags: typescript, javascript
Published: 2020-03-02 10:51:49

--- series: Advanced TypeScript Exercises ---

### 1. Conditional types solution ##
```ts
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](https://www.typescriptlang.org/play/index.html?ssl=16&ssc=30&pln=10&pc=1#code/C4TwDgpgBAwg9gOwGYEsDmUC8UDeAoKKBAQwFsIAuKAIzjgBsJiEBuAqe4gZ2BPKtoMmrPAF82oSFACqXCACcsudnwgB+Kj3koEaNoU49VGqFp16xbPABMIAY07zoSAK4I7wFIihoIwWQoAPOwwUBAAHsAQCNZcsIioaAA07AD6AHJkEAAKxPLASjAA2gDkqiUAumGR0bFQwPIu0GpQ2Sh2ANaBAEoQAI4uKE7WgQHyAHxJUGVZJeNQVDiiKYSpADLcwJnkufmFpYa8s1URUTFxDU1QLW2dPf2Dw6NyE1Mlh+Xzi6Ls4wAU7EIdgS6CoMDwAEoqBksrsCgAyKDrTbbHJ5YBWAD0mPqEB4UDs3DxeGBCHxLheSl8-hefxwRCyVEuECmH0ZUCQxHocigogheApCgAdKooNj6gALFBxVAQejWUwSuAueU0aAIRAAWjgYE8iC5ApeQrZ5DFOOAUplKDlCq4SpVCo1BWo0AtCmgzFt9tVLqgEvdBLgpDAKEYYXk8jgikAvBuARb28CTEOSXgAmKl+MZ0hn8eqNFkcTaqJl53n8wXyFMirJmyXSjnW1V25U+9VanV6kj0Q0KSsm6Dii112WN70K30ahDa3VeTsJ0nJhQAZnTNIUWaLHK5clZhfZzNL3fki6rpoHlvrNsVzcdcGdrv9TignqvDrVfoDwODoegCkjMfj5bHn2NaDlal5Nq+45ttO+pdomZIFOWAAsK6ZvSG6cty+Z9lQmE8nyh4oeKyEvi2YTBqAUBwNQABW9gFEsQA).

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 ##

```ts
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](https://www.typescriptlang.org/play/index.html?ssl=25&ssc=1&pln=1&pc=1#code/C4TwDgpgBAwg9gOwGYEsDmUC8UDeAoKKBAQwFsIAuKAIzjgBsJiEBuAqe4gZ2BPKtoMmrPAF82oSFACqXCACcsudnwgB+Kj3koEaNoU49VGqFp16xbPABMIAY07zoSAK4I7wFIihoIwWQoAFOx2iKhoVDhEZJRQwPIuECwc3LwxVEjE9HKieACUVAAKKHYA1gA8AEoQAI4uKE7W5QHyAHwANADkqp2tVrYOxE5Qru6e3r7+cvLBhKHI6JHR-CNZcsmGaSvxibkFUMVlVbX1jc3THZ2bPX14NvaOzm4eXgg+fi2zUPPhS6oZaySKSM6VW2Qge0i4juA0eI2e4zek0+ITCi1wy1iOyB11B2MhUGqdQaECaLVueAA9JS4hAeN9uHS8PN6S5pkpkdNAlF-nEEhB2sCtrFMuCoKI8ng2QoAHSqKDUuIACxQXBGKAg9GspiVcBcWpo0AQiAAtHAwIislLpjLceQFTTgCq1ahNdquLr9drjcBDcqFNBmO7PQbqNAlQHvnBSGAUIwoAp5HBFIBeDcAi3t3Fm+6XyABMHI+XJ5eP5grtWP54slOdzcpiDuVqvVbp1etDRtN5st9GtClr5YbTqbroNHrb2rDRE7FteVuZiFZ0wAzAWpkFiytRXIy6lediq735Eu6-bFUOXRrRyHvXBfZOnZGg62vX6I8NQjG49BE8moOnD8eA5ns6zZXuOfrGggZozogc5ZlAOYACyrp8G4ioCO4gpugIHkhDZ4WOL6ThAMagFAcDUAAVvYvo4KIQA)

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 `User`and say its required.
- `Required<User>` - we say we get `User` but with all fields non-optional

#### Utility types used in both solutions:
- [Pick](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktk) - allows for picking only wanted set of properties
- [Required](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredt) - produce a type with all properties required

***

Also want to mention more sophisticated solution by [Rahul Kashyap](https://dev.to/kashyaprahul94) left in the comment - [Solution from the comments section](https://www.typescriptlang.org/play/index.html#code/PTAEAkFMCdNAXAngB0gZ1GgFgewK4A2AJqLALYCGAlgHYJZxoVlyAi5AFBKqgDCONAMyoBzUAF5QAb3ahQNZpABcoAEY4cBSBRoBuGaAIU08eS2VqNW3ewC+ernACqaGOKn7TkAPzLj0WsJ6sobGnj6Y8P40gbZ6nChwANKQiGgA8gIAKtB4kABqFAS5aAA8maCQAB7wkDREGHyCIgB8bgAKVADGANZlADTusrIA2omgtKDdKTgCoJkAusqZo-MV1bX1CDlwXqBjyjSQAG4wtsNTiDNz881xDqDOMABKkPB40DSZCWVrNXUYj2gAx4vw2DX4QmErQkLwAjngqLAiCU0mQqPB+qAAKKVTpFIiQEoXK6ZAbE2bJVIZbK5ApFdAlHjNZm3djsEAQGBwAl4ijQCjwKj8BA4VRwTpYbTCSAkQC8G4BSXfYPMMsFAAjwNE6guF0vggJ+VT+m0BwNB-14EJaAAp9ENOpbhMoeOwAJTKQEvN4fL6oTFMuIcmrGUCdIzodj2mjBvAuaBuXWAq2SOQKZSRXIDEImVNqwouUA2F1xGMwAB0nlAgawVAwQkgxEwuEIJBUcBo-AAtDhkNr5AR2CXoKWsxWqzW1VR6yRsPgG+34GL6FzQNoSAB3RhNhuSk4hnBkZBUTQVaDQHBx2WARb22ZHo7GAEzx16J5OeNPbTNGbNmLa5AsugcH3LBRKzAeBq1rScGxnZtF3bGgux7IU+0AmB72HL9RzAiCJynRtZxbNtO27XtChvfg7xgABmJ89VjJMUx-AQ80gT9QhzdM4ELVDoCo4CWFA+hxzraCtxIedF3A5dV1ADd8NgndxX3Q9jxgM8L2vQc+JHECx0gvCYIbVs5GIpD+DIiMKIXQcABZaJfRilFzAgXDY78nOYlyuIA2zBN8wzCIqA8kFAHAVAAK0gLUpBsdggA). 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](https://dev.to/macsikora) and [twitter](https://twitter.com/macsikora).