Shen JinWei
Shen JinWei

Reputation: 15

Strange Result of TypeScript `extends` Operator (Testing Types Assignability)

I'm playing around with https://2ality.com/2020/06/computing-with-types.html#conditional-types to learn the type relationships in TypeScript.

Having defined the type function IsAssignableTo:

type IsAssignableTo<A, B> = A extends B ? true : false

I got the desired results like:

type MyGoodType1 = IsAssignableTo<42, Object>           // MyGoodType1 === true
type MyGoodType2 = IsAssignableTo<42, object>           // MyGoodType2 === false
type MyGoodType3 = IsAssignableTo<'foo', 'foo'|'bar'>   // MyGoodType3 === true

However, the result of reversing the parameters of the last expression:

type MyStrangeType = IsAssignableTo<'foo'|'bar', 'foo'> // MyStrangeType === boolean ???

is, to my surprise, neither literal true nor literal false (expecting it to be false), but a boolean?

My Questions are

  1. How assignability for union types works in TS? I've read SPEC's Assignment Compatibility and got no luck.
  2. How could the result of T1 extends T2 ? A : B become a union of A and B?

Complete Code in Playground

Upvotes: 1

Views: 64

Answers (1)

Ingo B&#252;rk
Ingo B&#252;rk

Reputation: 20043

Conditional types acting on generic arguments become distributive when given union types, i.e.,

IsAssignableTo<'foo' | 'bar', 'foo'> 
    = IsAssignableTo<'foo', 'foo'> | IsAssignableTo<'bar', 'foo'>
    = true | false
    = boolean

You can avoid that by wrapping your generic type into a one-tuple. Since the conditional is now no longer applied to a union, no distribution occurs:

type IsAssignableTo<A, B> = [A] extends [B] ? true : false;

You can also find this information in the handbook.

Upvotes: 1

Related Questions