Why this CustomExtract returns an different result from default Extract?

The difference is that Extract is a distributive conditional type, while your CustomExtract is not.

In order for a conditional type of the form X extends Y ? A : B to be distributive, the checked type X must be a “naked type parameter”; that is, a type parameter like T in interface Foo<T> {...}, and naked in that it is just the type parameter being checked (i.e., T extends ...) and not just some expression that includes the type parameter (e.g., Promise<T> extends ... or [T] extends ...).

As you surmised, distributive conditional types do indeed evaluate as the union of the conditional for each union element of the checked type T. So if F<T> is a distributive conditional type, then F<A | B | C> will be evaluated as F<A> | F<B> | F<C>. One potential catch is that F<never> will be evaluated as never no matter what the details of F are (as long as it’s distributive), as never is considered to be the “empty union type”.

For further information, see my other answer about what distributive conditional types are and how they work.

Leave a Comment