loading...

Advanced TypeScript Exercises - Answer 7

macsikora profile image Maciej Sikora ・2 min read

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

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
}

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 }

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

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 dev.to and twitter.

Posted on by:

macsikora profile

Maciej Sikora

@macsikora

I am Software Developer, currently interested in static type languages (TypeScript, Elm, Reason) mostly in the frontend land. I am available for mentoring, I can help with type systems and FP.

Discussion

pic
Editor guide
 

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

 

you can do it in one line

function takeSomeTypeOnly<T extends SomeType>(x: SomeType extends T ? T : never)
  { return x }
 

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

 

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 🛑 
}
 

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!

 

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

 

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