Skip to content

Index Signature Fails with Generics and Intersection Types #23673

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

Closed
AnyhowStep opened this issue Apr 25, 2018 · 1 comment
Closed

Index Signature Fails with Generics and Intersection Types #23673

AnyhowStep opened this issue Apr 25, 2018 · 1 comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@AnyhowStep
Copy link
Contributor

TypeScript Version: Version 2.9.0-dev.20180405

Search Terms: extends generic intersection index

Code

type SomeType<T> = {
    [k in keyof T]: any;
};

function generic<Base, Derived extends SomeType<Base>>() {
    const derived: Derived = null as any;
    const test: { test: string } = null as any;
    const both: Derived & { test : string } = null as any;

    const works0: SomeType<Base> = derived;
    const works1: SomeType<Derived> = derived;
    const works2: SomeType<{ test: string }> = test;

    //This fails unexpectedly    
    const fails0: SomeType<Base & { test: string }> = both;
}

interface ConcreteBase {
    a: string,
    b: string,
}
interface ConcreteDerived {
    a: string,
    b: string,
    c: string,
}
const derived: ConcreteDerived = null as any;
const test: { test: string } = null as any;
const both: ConcreteDerived & { test : string } = null as any;

const works0: SomeType<ConcreteBase> = derived;
const works1: SomeType<ConcreteDerived> = derived;
const works2: SomeType<{ test: string }> = test;

const worksOutFine: SomeType<ConcreteBase & { test: string }> = both;

Expected behavior:

fails0 in generic() should compile

Actual behavior:

fails0 in generic() fails

Playground Link: Link here

Intuitively, to me, it should work out fine.

  • Derived has all the fields of Base; possibly more.
  • I added one extra field test.
  • Derived is assignable to Base
  • Derived & { test: string } should be assignable to Base & { test: string }
@mhegazy mhegazy added this to the TypeScript 2.9 milestone Apr 26, 2018
@mhegazy mhegazy added the Bug A bug in TypeScript label Apr 26, 2018
@weswigham
Copy link
Member

So the way we break down intersections makes it impossible to recognize the equivalence here. We compare the intersection one member at a time and see if either member on their own is assignable to the SomeType intersection. {test: string} isn't assignable - it's not guaranteed to have Base's props. Derived isn't assignable because it's missing test (keyof Base | "test" is not assignable to keyof Derived).

@ahejlsberg have we just been marking issues like this as a design limitation, or are we planning to do something about it?

@mhegazy mhegazy modified the milestones: TypeScript 3.0, TypeScript 3.1 Jul 2, 2018
@RyanCavanaugh RyanCavanaugh added Design Limitation Constraints of the existing architecture prevent this from being fixed and removed Bug A bug in TypeScript labels Aug 23, 2018
@RyanCavanaugh RyanCavanaugh removed this from the TypeScript 3.1 milestone Aug 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

4 participants