DEV Community

Pragmatic Maciej
Pragmatic Maciej

Posted on

Advanced TypeScript Exercises - Answer 7

The question was about exclusive behavior of the type. The core thing is to understand is the never type. Never is an bottom type, so type which has no values, like an empty set. In other words - we cannot assign anything to the type never.

const x: never = 🕳 // there is no possible value to make compiler happy
Enter fullscreen mode Exit fullscreen mode

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

type EmptyObject = {
    [K in PropertyKey]: never
Enter fullscreen mode Exit fullscreen mode

EmptyObject type is a mapped type, 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

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 }
Enter fullscreen mode Exit fullscreen mode

In the solution we again are using mapped type, 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:

type Exclusive<T1, T2 extends T1> = T2 & Record<Exclude<keyof T2, keyof T1>, never>;
Enter fullscreen mode Exit fullscreen mode

We use Record utility type and Exclude 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

Thank you Manolo Edge 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 and twitter.

Top comments (8)

jrumandal profile image
John Ralph Umandal

**palmface** I was strictly trying to touch only the line of function takeSomeTypeOnly.

These challenges are really nice, but please be specific with what we can and cannot do. D:

// change below function type definition 🔥 in order to allow only strict SomeType value
I might be the one misunderstanding.

Thanks anyway! Your exercises keep my brain running

alextsk profile image

you can do it in one line

function takeSomeTypeOnly<T extends SomeType>(x: SomeType extends T ? T : never)
  { return x }
Enter fullscreen mode Exit fullscreen mode
arthurka profile image

Nice try. Don't work.

const x2 = { prop: 'a' } as const;
Enter fullscreen mode Exit fullscreen mode
macsikora profile image
Pragmatic Maciej

Thanks for the comment. Sorry if smth was not clear.

kashyaprahul94 profile image
Rahul Kashyap

Thanks for the answers Maciej.

However the first solution doesn't complain 😢 if i use this input -

const shouldFail: EmptyObject = {
    prop: (5 as never) // here we should have compile error 🛑 
macsikora profile image
Pragmatic Maciej

Good hack Rahul. Unfortunately you can also do the same for all these solution and hack them. I don't think it is possible to prevent such, in the same way we can hack almost every type by as any as X thing.

In any way I think the wanted behavior was achieved, even though we can hack it, the hack is explicitly visible in the code.

But thanks for the comment!

nombrekeff profile image

Cool stuff! I'm liking the series! It's getting advanced

annagit profile image

thank you, these are advanced indeed 🔥🔥 and super interesting :)