Although my knowledge of typescript is limited, I decided to give it a try in the playground following @jcalz's input.
Upon exploring, I noticed that:
type LookUp<U, T extends string> = U extends { type: string } ? U["type"] extends T ? U : never : never
type LookUpWrong<U extends { type: string }, T extends string> = U extends { type: string }? U["type"] extends T ? U : never : never
type Animal = { type: 'dog' } | { type: 'cat' }
type Banimal = { type : 6};
type ValidResultLookUp = LookUp<Animal, 'dog'> // { type: 'dog' }
type ValidResult2LookUpWrong = LookUpWrong<Animal, 'dog'> // {type:'dog'}
const obj:ValidResultLookUp = {type:'dog'};
const obj2:ValidResult2LookUpWrong = {type:'dog'};;
type invalidResultLookUp = LookUp<Banimal,'dog'> // doesn't give error since it's just U which Banimal satisfies
type invalidResultLookUpWrong = LookUpWrong<Banimal,'dog'> // gives error before hand since Banimal doesn't extend {type:string}
If you reformat LookUpWrong
to match LookUp
with the additional conditional check U extends {type:string}
, both types work as expected when used to construct ValidResultLookUp
and ValidResult2LookUpWrong
. This is because the Animal
type fulfills the {type:string}
requirement of the condition.
Introducing this conditional check in LookUpWrong
activates the distributive conditional types property, changing the behavior as follows:
type someType = 'dog' | 'cat' extends 'dog' ? 'desiredType' : never;
someType
will now be
never
Instead, we see the following:
type someType = 'dog' extends 'dog' ? 'desiredType' : never;
The presence of
cat
is irrelevant here as
dog
extending itself due to distribution results in a truthy condition and yields
desiredType
.
Consider the case of Banimal
, where {type:6}
. Using LookUp
does not trigger an error when creating invalidResultLookUp
because U
does not adhere to
{type:string}</code unlike <code>LookUpWrong
(in the generics section).
Hence, the conditional check (for distributive conditional effect) is essential in LookUpWrong
, preventing incorrect type assignments while building other types due to the added U extends {type:string}
safeguard.
Explore the playground through this link.