Skip to content

identical conditional types not assignable to each other #21756

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
tvald opened this issue Feb 8, 2018 · 4 comments
Closed

identical conditional types not assignable to each other #21756

tvald opened this issue Feb 8, 2018 · 4 comments
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@tvald
Copy link

tvald commented Feb 8, 2018

Identical conditional types are not assignable to each other.

TypeScript Version: 2.8.0-dev.20180208

Code

type Foo<T> = T extends string ? boolean : number;
type Bar<T> = T extends string ? boolean : number;
const convert = <T>(value: Foo<T>): Bar<T> => value; // this fails

type Baz<T> = Foo<T>;
const convert2 = <T>(value: Foo<T>): Baz<T> => value; // this passes

Expected behavior:
no errors

Actual behavior:

TypeScript $ ./node_modules/.bin/tsc --noEmit test.ts
test.ts(4,47): error TS2322: Type 'Foo<T>' is not assignable to type 'Bar<T>'.
  Type 'number | boolean' is not assignable to type 'Bar<T>'.
    Type 'number' is not assignable to type 'Bar<T>'.
@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Feb 8, 2018

IMHO, if a conditional type is already resolved, compare the resolved type.

If target type is an unresolved conditional type, compare the source type:

  1. if source type is not unresolved conditional type, it can be assigned to the target if the type can be both assigned to true type and false type,
  2. if source type is unresolved conditional type, it can be assigned to the target if its branch types can be correspondingly assigned to target's branch types.

But this usage sounds weird, @tvald could you please give a concrete example where you need to assign/compare two conditional types?

@mhegazy mhegazy added the Needs More Info The issue still hasn't been fully clarified label Feb 8, 2018
@tvald
Copy link
Author

tvald commented Feb 8, 2018

This is the particular case:

// lib/es5.d.ts
declare type PromiseConstructorLike = new <T>(executor: (
  resolve: T extends void ? (value?: PromiseLike<void>) => void : (value: T | PromiseLike<T>) => void,
  reject: (reason?: any) => void) => void
) => PromiseLike<T>;

// lib/es2015.promise.d.ts
interface PromiseConstructor {
  new <T>(executor: (
    resolve: T extends void ? (value?: PromiseLike<void>) => void : (value: T | PromiseLike<T>) => void,
    reject: (reason?: any) => void) => void
  ): Promise<T>;
}

It's reasonable to expect interoperability across compatible type definitions - perhaps originating from different libraries, perhaps narrowed from more complex types. Not supporting structural comparison of conditional types feels like a significant deviation from the way the rest of the type system works.

@mhegazy mhegazy added Bug A bug in TypeScript and removed Needs More Info The issue still hasn't been fully clarified labels Feb 8, 2018
@mhegazy mhegazy added this to the TypeScript 2.8 milestone Feb 8, 2018
@mhegazy
Copy link
Contributor

mhegazy commented Feb 8, 2018

This is behaving as intended, but i think we should reconsider.

@ahejlsberg
Copy link
Member

I agree, two conditional types should be identical if they have the same four constituent types and the same distributivity (i.e. both are distributive or both are not). Pretty easy to fix, we already have logic in place to intern conditional types, it just needs a bit of tweaking.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

4 participants