Skip to content

Nested Exclude has unexpected behavior #28824

@ghost

Description

TypeScript Version:

$ tsc --version
Version 3.3.0-dev.20181122

Search Terms:
unexpected, exclude
Code

/*
  Some basic definitions of unions
*/
type Union = 'a' | 'b';
type Product<A extends Union, B> = { f1: A, f2: B};
type ProductUnion = Product<'a', 0> | Product<'b', 1>;

/*
  These work as I would expect. Each element in the union is mapped
  the complement or the double complement with nested Exclude
*/
type UnionComplement = {
  [K in Union]: Exclude<Union, K>
};
// {a: "b"; b: "a"}
type UnionComplementComplement = {
  [K in Union]: Exclude<Union, Exclude<Union, K>>
};
// {a: "a"; b: "b"}

/*
  This also works as I would expect
*/
type ProductComplement = {
  [K in Union]: Exclude<ProductUnion, { f1: K }>
};
// {a: Product<'b', 1>; b: Product<'a', 0>}

/*
  Double complement on the other hand doesn't work
*/
type ProductComplementComplement = {
  [K in Union]: Exclude<ProductUnion, Exclude<ProductUnion, { f1: K }>>
};
// {a: ProductUnion; b: ProductUnion}

/*
  Explicit inlining works as I would expect
*/
type First = Exclude<ProductUnion, Exclude<ProductUnion, { f1: 'a' }>>;
// {f1: 'a'; f2: 0}
type Second = Exclude<ProductUnion, Exclude<ProductUnion, { f1: 'b' }>>;
// {f1: 'b'; f2: 1}

/*
  Making parametrized types works as I would expect
*/
type Complementor<T> = {
    [K in Union]: Exclude<T, { f1: K }>
};
type DoubleComplementor<T> = {
    [K in Union]: Exclude<T, Exclude<T, { f1: K }>>
};
type Complement = Complementor<ProductUnion>;
// {a: Product<'b', 1>; b: Product<'a', 0>}
type DoubleComplement = DoubleComplementor<ProductUnion>;
// {a: Product<'a', 0>; b: Product<'b', 0>}

Expected behavior:
I would expect the parametrized and non-parametrized type to work the same way but that's not
the case.

Actual behavior:
See the comments.

Playground Link: link

Related Issues: Some issues related to Pick and Exclude but didn't seem to apply.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptDomain: Conditional TypesThe issue relates to conditional typesFixedA PR has been merged for this issue

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions