Skip to content

Cannot assign type which should be compatible when conditional generics are used #50672

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
EnkeyMC opened this issue Sep 7, 2022 · 4 comments
Labels
Duplicate An existing issue was already created

Comments

@EnkeyMC
Copy link

EnkeyMC commented Sep 7, 2022

Bug Report

Cannot assign type which should be compatible when conditional generics are used (also posted on SO but was only suggested to open issue here)

🕗 Version & Regression Information

Throws error on all versions available in TypeScript playground.

Playground Link

Playground Link

💻 Code

// Returns keyes that have type extending Types
type KeysMatching<T, Types> = { [K in keyof T]: T[K] extends Types ? K : never }[keyof T];

type Mapping = {
    STR: string;
    NUM: number;
    BOOL: boolean;
}

type Values = Mapping[keyof Mapping];

type Generic<T extends Values> = {
    typeStr: KeysMatching<Mapping, T>
}

const foo: Generic<boolean> = { typeStr: 'BOOL' };
const bar: Generic<Values> = foo;
// Type 'Generic<boolean>' is not assignable to type 'Generic<Values>'.
//  Type 'Values' is not assignable to type 'boolean'.
//    Type 'string' is not assignable to type 'boolean'.(2322)

// This works fine
type Conditional<T, V> = T extends V ? T : unknown;
const foo2: Conditional<string, Values> = 'string';
const bar2: Conditional<Values, Values> = foo2;

🙁 Actual behavior

TS throws error that foo is not assignable to bar

🙂 Expected behavior

TS does not throw error as the types should be compatible

@whzx5byb
Copy link

whzx5byb commented Sep 7, 2022

A shorter repro:

type V<T> = { value: 0 extends T ? T : never };
type V0 = V<0>; // V0 = { value: 0 }
type VNumber = V<number>; // VNumber = { value: number }

type R1 = V<0> extends V<number> ? true : false;
//   ^?
type R2 = V0 extends VNumber ? true : false
//   ^?

Expect both to be true but R1 is false.

Related: #48070

@fatcerberus
Copy link

fatcerberus commented Sep 7, 2022

Probably something to do with variance measurement - it seems like V<T> is incorrectly being measured as contravariant/invariant in T, likely because T occurs on the RHS of an extends check. R2 is correctly determined to be true because V0 extends VNumber bypasses variance measurement and does a full structural check.

@andrewbranch
Copy link
Member

Yeah, duplicate of #48070

@andrewbranch andrewbranch added the Duplicate An existing issue was already created label Sep 9, 2022
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants