Skip to content
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

CLI-only error calling generic function #27507

Open
ghost opened this issue Oct 2, 2018 · 6 comments
Open

CLI-only error calling generic function #27507

ghost opened this issue Oct 2, 2018 · 6 comments
Labels
Bug A bug in TypeScript Domain: Mapped Types The issue relates to mapped types
Milestone

Comments

@ghost
Copy link

ghost commented Oct 2, 2018

TypeScript Version: 3.2.0-dev.20181002

Code

function getFirst<K extends string, T>(obj: Record<K, ReadonlyArray<T>>, key: K): T {
	return obj[key][0];
}

interface I {
	readonly n: ReadonlyArray<number>;
	readonly s: ReadonlyArray<string>;
}

function f(i: I): number {
   return getFirst(i, "n");
}

Expected behavior:

No error.

Actual behavior:

No error in the editor.
Error on the command line:

src/a.ts:11:20 - error TS2345: Argument of type 'I' is not assignable to parameter of type 'Record<"n", ReadonlyArray<string>>'.
  Types of property 'n' are incompatible.
    Type 'ReadonlyArray<number>' is not assignable to type 'ReadonlyArray<string>'.
      Type 'number' is not assignable to type 'string'.

11    return getFirst(i, "n");

Related Issues: #19686

@ghost ghost added Bug A bug in TypeScript Domain: Mapped Types The issue relates to mapped types labels Oct 2, 2018
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 3.2 milestone Oct 10, 2018
@ahejlsberg
Copy link
Member

Here's what's going on with this one: During inference from type I to Record<K, ReadonlyArray<T>> we end up inferring from the union type ReadonlyArray<number> | ReadonlyArray<string> to T. That causes us to infer number and string for T, in that order. When we have disjoint inferences we always pick the first one, so we go with number and things work. At least in the IDE case.

The reason it fails with the command-line compiler is that we check lib.d.ts (and others) before the program itself, and during those checks we end up materializing the type ReadonlyArray<string>. Thus it ends up having a lower type id than ReadonlyArray<number>, and our union type flips around and becomes ReadonlyArray<string> | ReadonlyArray<number>. Which in turn causes us to infer string for T and we now get an error.

The reason we don't get an error in the IDE is that we ask for errors for the current file first so type ids end up following the textual ordering. For the same reason, the error goes away if you specify --skipLibCheck with the command-line compiler.

@ahejlsberg
Copy link
Member

@RyanCavanaugh @DanielRosenwasser We may want to discuss this one in the design meeting.

@weswigham
Copy link
Member

Discuss having a stable order for type ids that doesn't depend on check order or altering inference to not just "choose the first type"? Or the issue in general?

@ahejlsberg
Copy link
Member

@weswigham Well, I don't see type ids ever having a stable sort order, so really we want to free ourselves from any dependencies on type id ordering. Which for example means we should never depend on the order of types in a union type.

@sledorze
Copy link

Whats the 'take the first type' motivation? (Looks like a can of worms to me)

@RyanCavanaugh
Copy link
Member

Rewritten version that is stable between CLI/server

type FetchArr<T, K extends keyof T> = T extends { [x in K]: ReadonlyArray<infer E> } ? E : void;  

function getFirst<T, K extends keyof T>(obj: T, key: K): FetchArr<T, K> {
	return obj[key][0];
}

interface I {
	readonly n: ReadonlyArray<number>;
	readonly s: ReadonlyArray<string>;
}

function f(i: I): number {
  return getFirst(i, "n");
}

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: Mapped Types The issue relates to mapped types
Projects
None yet
Development

No branches or pull requests

5 participants