Advanced TypeScript Exercises - Answer 7
Tags: javascript, typescript
Published: 2020-03-13 08:36:09

--- series: Advanced TypeScript Exercises ---

The question was about exclusive behavior of the type. The core thing is to understand is the `never` type. `Never` is an [bottom type](https://en.wikipedia.org/wiki/Bottom_type), so type which has no values, like an empty set. In other words - we cannot assign anything to the type `never`. 

```ts
const x: never = 🕳 // there is no possible value to make compiler happy
```
We will use `never` in order to achieve the wanted exclusive type behavior.

## Answer 7.1 - type which will allow only for a empty object value
```ts
type EmptyObject = {
    [K in PropertyKey]: never
}
```
`EmptyObject` type is a [mapped type](https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types), which for every key has value type `never`. Every key here is represented by `K in PropertyKey` as `PropertyKey` represents all possible keys of objects. We could be using `[K in any]` with the same effect. In result our type for every key allows the value to be `never`, therefor there is no possibility to put any key into the object, as we have no instance of `never` bottom type.

## Answer 7.2 - change function type to be exclusive for its argument

```ts
type Exclusive<T1, T2 extends T1> = {
    [K in keyof T2]: K extends keyof T1 ? T2[K] : never 
}
function takeSomeTypeOnly<T extends SomeType>(x: Exclusive<SomeType, T>) { return x }
```
In the solution we again are using [mapped type](https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types), we say that argument is something which extends `SomeType` and we put it into `Exclusive` type level function which is doing the needed transformation. Exactly `[K in keyof T2]: K extends keyof T1 ? T2[K] : never`, so for every key in `T2` we check if this key is also in `T1`(the wanted type) if it is we pass it, if not we put `never`, it means that such property will always be invalid.

Alternative version of `Exclusive` can look like that:
```ts
type Exclusive<T1, T2 extends T1> = T2 & Record<Exclude<keyof T2, keyof T1>, never>;
```
We use [Record](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkt) utility type and [Exclude](https://www.typescriptlang.org/docs/handbook/utility-types.html#excludetu) utility type in order to make mapped type with all keys invalid for `T1` so with `never` value type. Joining it with `T1` gives us the same result - keys which are not in wanted type have `never` value.

The full code can be found - [The Playground](https://www.typescriptlang.org/play/index.html?ssl=23&ssc=86&pln=23&pc=1#code/PTAEHYDoEZQYQE4FMCGAXJo0E8AOmB3ACwEsBjI0AkgGxtBToHsDQmA7G7UAMyYQagkAW1w42AIwBWSMmlAA3RgFckAKDU58oAKKicAeWmz5AXlABvNaBugA2gGlQJdqAAKCJvgQ4HSbAC6AFyg7EgKSAhqAL6gIEL63EzGcmyc2AA0oIC8G4Cku6AUKOwA5phoRGV4ZUygEphIAB5kNMoAziQRvPwM7Nw8JEg0ACagGvEYrfJkKK1IrWpkHJOgrURMysNuM60hemLYRjKp5hbRANxxYOUkrStrGyN1bADWOYBH+wtL8qvrwwBiKFou0ShxMoBO1lsuE8uBCsHiFWQVEwPweoCIKE6i1EtHqCE8AmygEW90bRDRqeJQABM8AxJUwPGU7DkJA4WCqWBqT0aLXanT4AhIaFuKAQxWUwiQ7DQGi0mAAykxJQAVDnmSyQmzQrwhSYIFzFGKaDk6Jq8jpIAA8yugWWVNMaGHYQ1uNoAfOCNbZ7E4XKBnv4mDxQPbgqAnI6pS7-YHgzbQAB+ENUxwBUAhMIRARG+KMDAIdjoC3G7Sm5ptC1U6225NCBpO6Puz320AAMlAACVZPwhpayy0hlaA9gg8mssPR+6spnIm6zmMwIV6bVBixeEyWWy5aBB-12ELWa48s5XD3IpyGMxWBwuCs0PrUoqVRylC11IzmWhD1gUAGn0hVXwAx0mtOsG1uf9AKQN0AAoGl2M0KwiS1IKqO03QASksUBkDQZQC1ABpQDJT52GWIiTlAbVYVAAByFBaOI+c0F-JBUKA9I4Kw8ZSFuVFhhXF53g0RYyPkbhKOokJ6NorIUCGBSDw4RgPB1OiGkY85NFY9ikGArgYOwbiwERQgUXuASMSxJVcFxIR8W6YlQCAA)

Thank you [Manolo Edge](https://dev.to/nombrekeff) for the good answer and taking the challenge.

**This series 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).