Skip to content

Generic type alias produces erroneously compatible types #31006

Closed
@jcalz

Description

@jcalz

TypeScript Version: 3.5.0-dev.20190417

Search Terms:
generics, resolved, nested generics, specified, assignable, type safety, type alias, compatible

Code

interface A { a: number; }
interface B { b: string; }

type Demo<T> = <K extends keyof T> (key: K, val: T[K]) => void

// Demo<A> should not be assignable to Demo<B>, but it is?!
declare const implDemoA: Demo<A>;
const implDemoB: Demo<B> = implDemoA; // no error!? 😕

Expected behavior:
There should be an error that a type Demo<A> is not assignable to Demo<B>.

Actual behavior:
It compiles with no error.

I guess the compiler "forgets" what concrete type T is, since it doesn't appear directly in the resulting type. If one manually substitutes A and B for T into the definition of Demo<T> to make DemoA and DemoB, everything behaves as expected:

// Note that we can manually make a concrete type DemoA and DemoB:
type DemoA = <K extends keyof A>(key: K, val: A[K]) => void;
type DemoB = <K extends keyof B>(key: K, val: B[K]) => void;

type MutuallyAssignable<T extends U, U extends V, V = T> = true;
// the compiler agrees that DemoA and Demo<A> are mutually assignable
declare const testAWitness: MutuallyAssignable<Demo<A>, DemoA>; // okay
// the compiler agrees that DemoB and Demo<B> are mutually assignable
declare const testBWitness: MutuallyAssignable<Demo<B>, DemoB>; // okay

// And the compiler *correctly* sees that DemoA is not assignable to DemoB
declare const implDemoAConcrete: DemoA;
const implDemoBConcrete: DemoB = implDemoAConcrete; // error as expected
//    ~~~~~~~~~~~~~~~~~ <-- Type 'DemoA' is not assignable to type 'DemoB'.

This comes from a question on Stack Overflow.

Playground Link:
👩‍💻🔗

Related Issues:
I'm not finding anything I am confident is related: 🔍👀∅⁉

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issueFixedA PR has been merged for this issueRescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions