Skip to content

mixing generics, Pick, Exclude and intersection types fails to compile in 3.1.0 #28274

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
seansfkelley opened this issue Oct 31, 2018 · 3 comments
Assignees
Labels
Bug A bug in TypeScript Domain: Indexed Access Types The issue relates to accessing subtypes via index access
Milestone

Comments

@seansfkelley
Copy link

seansfkelley commented Oct 31, 2018

TypeScript Version: 3.2.0-dev.20181031

Search Terms: generic pick exclude keyof intersection spread

Code

type TWithFoo<T> = Pick<T, Exclude<keyof T, "foo">> & { foo: string };

const foobar: TWithFoo<{ foo: number; bar: string }> = {
  foo: "foo",
  bar: "bar",
};

function strictSpread<T, K extends keyof T>(
  original: T,
  override: Pick<T, K> | T
): T {
  return Object.assign({}, original, override);
}

// Works as expected.
strictSpread(foobar, {
  foo: "foo",
  bar: "bar",
});

// Fails as expected.
strictSpread(foobar, {
  baz: "foo",
});

function fn<T extends object>() {
  const o: TWithFoo<T> = null as any;
  // Fails unexpectedly.
  strictSpread(o, {
    foo: "foo",
  });
}

Expected behavior:

The line annotated "fails unexpectedly" should compile successfully.

AFAICT this change happened between 3.1.0-dev.20180825 and 3.1.0-dev.20180828.

Actual behavior:

The line annotated "fails unexpectedly" does not compile, though it used to in earlier versions.

The error reported is

Type '"foo"' is not assignable to type 'T["foo"] & string'.
  Type '"foo"' is not assignable to type 'T["foo"]'.

But TWithFoo is specifically defined to ignore any existing foo key and replace it with string.

Playground Link: link

Related Issues: #27201, #27928

@weswigham weswigham added Bug A bug in TypeScript Domain: Indexed Access Types The issue relates to accessing subtypes via index access labels Nov 1, 2018
@weswigham
Copy link
Member

My comment in #27201:

Because Exclude is imperfect and can't currently track constraints on the false branch of the conditional (in a generic fashion), as those are (effectively) subtraction types, which we can't easily express right now. :(

Our more correct checking of generic indexed accesses is probably what caused the issue to appear. But what we want to execute here is that the T in T["foo"] is a T that can never have a "foo" property, so T["foo"] must always be unknown (which can then combine with string to just be string). Certainly fixable if we start tracking the false-branch implied constraints, I think.

@seansfkelley
Copy link
Author

Ah, interesting; I missed that comment originally. I'll see if the actual code this is derived from can be expressed with Extract instead to see if it works. Feel free to close this issue as duplicate if you think it is!

@apexskier
Copy link

I'm not sure, but I think I've found the same issue in v3.3.1. Please let me know if I'm wrong and I can open a new issue. This is a minimal reproduction, my real use case has the Exclude<Exclude type generated from nested react higher order components.

playground

interface Base {
    a: number;
    b: number;
    c: number;
    d: number;
    e: number;
    f: number;
}

type BaseA = Exclude<keyof Base, "a" | "c" | "b" | "d">;
type BaseB = Exclude<Exclude<keyof Base, "a" | "b">, "c" | "d">;

function testingBase(a: BaseA): BaseB {
    return a; // works, as expected
}

type A<T> = Exclude<keyof T, "a" | "c" | "b" | "d">;
type B<T> = Exclude<Exclude<keyof T, "a" | "b">, "c" | "d">;

function testing<T>(a: A<T>): B<T> {
    return a; // fails unexpectedly with "Type 'Exclude<keyof T, "a" | "b" | "c" | "d">' is not assignable to type 'Exclude<Exclude<keyof T, "a" | "b">, "c" | "d">'."
}

@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Mar 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: Indexed Access Types The issue relates to accessing subtypes via index access
Projects
None yet
Development

No branches or pull requests

5 participants