Skip to content

Nested Exclude has unexpected behavior #28824

Closed
@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

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions