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

Interface with methods interferes with string literal type inference #19497

Closed
wolfgang42 opened this issue Oct 26, 2017 · 8 comments
Closed
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@wolfgang42
Copy link

TypeScript Version: 2.7.0-dev.20171026

Minimal example:

interface Observable<T> {peek(): T}
declare function obs<T>(val: T): Observable<T>
const t: Observable<'A'> = obs('A')

Expected behavior:
Compilation without errors.

Actual behavior:

src/test.ts(3,7): error TS2322: Type 'Observable<string>' is not assignable to type 'Observable<"A">'.
  Type 'string' is not assignable to type '"A"'.

This error goes away if the interface has no methods or function signature:

interface Observable<T> {}

Alternately, you can redundantly specify the type of the argument to obs():

const t: Observable<'A'> = obs('A' as 'A')
@ghost
Copy link

ghost commented Oct 26, 2017

We've had some issues about string literal types in the past but this seems like a new one:

declare function id<T>(val: T): T
declare function arr<T>(val: T): T[]
const x: "a" = id("a");
const y: "a"[] = arr("a");

x works but y doesn't. Temporarily marking as a bug.

@ghost ghost added the Bug A bug in TypeScript label Oct 26, 2017
@ahejlsberg
Copy link
Member

This is a design limitation and is working as intended. See #10676 for context. In the original example we can't tell that T is used only in output positions within Observable<T>. Therefore we widen from 'a' to string. As you point out, you can force the desired result by writing 'a' as 'a'. It would be nice to do better here, but it isn't clear how we could cheaply and consistently determine that a type parameter is used only in output positions.

@ahejlsberg ahejlsberg added Design Limitation Constraints of the existing architecture prevent this from being fixed and removed Bug A bug in TypeScript labels Oct 26, 2017
@ahejlsberg
Copy link
Member

@andy-ms Your example is working as it should. Array elements are mutable locations so widening is to be expected.

@ghost
Copy link

ghost commented Oct 26, 2017

This doesn't seem to be affected by mutability?

declare function arr<T>(val: T): ReadonlyArray<T>
const y: ReadonlyArray<"a"> = arr("a"); // Error

Observable also only returns a T, not exposing it as a property.
Edit: Oh, I see:

it isn't clear how we could cheaply and consistently determine that a type parameter is used only in output positions.

@kpdonn
Copy link
Contributor

kpdonn commented Nov 1, 2017

@wolfgang42 Another potential workaround for your example if you are only expecting strings is:

interface Observable<T extends string> {peek(): T}
declare function obs<T extends string>(val: T): Observable<T>
const t: Observable<'A'> = obs('A') // now works

@wolfgang42
Copy link
Author

@kpdonn The Observable in my example was actually from a library, so I can't change its declaration. Hopefully someone else will find that useful, though.

[I've since had to rewrite the code that had this issue for other reasons, this is not currently a problem for me any more.]

@ghost
Copy link

ghost commented Nov 7, 2017

Another case:

declare function createArray<T>(): Array<T>;
interface I {
    a: number;
    b: true[];
}

const x: I = { a: 0, b: createArray() };
src/a.ts(7,7): error TS2322: Type '{ a: number; b: boolean[]; }' is not assignable to type 'I'.
  Types of property 'b' are incompatible.
    Type 'boolean[]' is not assignable to type 'true[]'.
      Type 'boolean' is not assignable to type 'true'.

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

4 participants