2

Below is the implementation of Exclude floating around on various blogs ( One Reference)

type Exclude<T, U> = T extends U ? never : T; According to Typescript blog, it constructs a new type by excluding some properties from the union type. Perfect, I get it.

Let's detail this out.

If T extends U it returns never. Fair enough. Extends means that we are inheriting all properties. ( Reference - https://stackoverflow.com/a/38834997/1096194)

Confusion is that if ternary condition returns false, Shouldn't it return T - U instead of T as we may want to return only T - U properties in case T is not an extension of U.

Let's take an example #1

U = "name", T = "id" | "name";

If I understand correctly, T extends U is false in this case as T did not inherit all properties from U. So, we should return T-U i.e. "id" which is the desired output of exclude operator.

Let's take another example #2

U = "name", T = "id" | "email"

In this case too, ternary fails as the T does not extend or inherits anything from U. So it should return T - U i.e. id | email happens to be equal to T in this case.

So, what is the correct definition anyway i.e. T extends U? never: T or T extends U? never: T - U?

kaya3
  • 47,440
  • 4
  • 68
  • 97
HalfWebDev
  • 7,022
  • 12
  • 65
  • 103
  • 3
    I'm not sure your question is clear. Are you asking about [distributivity of conditionals over unions](https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types)? The first paragraph in the documentation should explain why the original definition works. – Tiberiu Maran Feb 25 '20 at 08:42
  • This answers my question. Was not aware of "distributivity of conditionals over unions?" – HalfWebDev Feb 25 '20 at 09:55

1 Answers1

1

As @artcorpse said in the comments, conditional types are resolved like this:

with T = A | B | C;

T extends U ? X : Y

means

(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)

So in your example:

U = "name";
T = "id" | "name";

T extends U ? X : Y
=>
("id" extends "name" ? never | "id") | ("name" extends "name" ? never | "id")
=>
"id" | never
=>
"id"

https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types

"In instantiations of a distributive conditional type T extends U ? X : Y, references to T within the conditional type are resolved to individual constituents of the union type (i.e. T refers to the individual constituents after the conditional type is distributed over the union type)."

Roberto Zvjerković
  • 9,657
  • 4
  • 26
  • 47