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

string literal type defined via a mapped type is sometimes erroneously interpreted as simply string #16553

Closed
seansfkelley opened this issue Jun 15, 2017 · 3 comments
Labels
Duplicate An existing issue was already created

Comments

@seansfkelley
Copy link

seansfkelley commented Jun 15, 2017

A "direct" string literal type defined using type Foo = "A"; behaves properly in more places than an apparently-equivalent "indirect" string literal type defined using mapped types.

TypeScript Version: 2.3.4

Code

I discovered this issue while using https://github.com/dphilipson/typescript-string-enums, and as such, have inlined the relevant part of the library into the top of the example.

// Inlined, stripped-down version of the relevant part of typescript-string-enums.

function Enum<V extends string>(...values: V[]): { [K in V]: K };
function Enum<
    T extends { [_: string]: V },
    V extends string
>(definition: T): T;
function Enum(...values: any[]): object {
   // ... elided for brevity ...
   return {} as any;
}

type Enum<T extends object> = T[keyof T];



// Version 1: Using a "direct" string literal type.

// type MyEnum = "ENUM";



// Version 2: Using an "indirect" string literal type.

const MyEnum = Enum("ENUM",);
type MyEnum = Enum<typeof MyEnum>;



// The offending code sample.

interface MyInterfaceWithEnum {
    foo: MyEnum;
}

function parseToEnum(s: string): MyEnum {
    return null as any;
}

function failingFunctionWithMap(s: string): MyInterfaceWithEnum[] {
    // This block fails to compile when using an "indirect" string literal type, claiming that
    //     Type 'string' is not assignable to type '"ENUM"'.
    // This implicit change in type does not happen with the "direct" string literal type.
    return [""].map((i) => ({
        // Note that VSCode correctly reports the output of `parseToEnum` here for both enums.
        foo: parseToEnum(i),
    }));
}

function successfulFunctionWithoutMap(s: string): MyInterfaceWithEnum {
    // This block always compiles, using either of the "direct" or "indirect" string literal types.
    return {
        foo: parseToEnum(s),
    };
}

Expected behavior:

Both definitions of MyEnum are equal and interchangeable.

Actual behavior:

The "indirect" type erroneously fails to compile in one of the two functions.

@seansfkelley seansfkelley changed the title string literal string literal type defined via a mapped type is sometimes erroneously interpreted as simply string Jun 15, 2017
@DanielRosenwasser
Copy link
Member

I believe that this is a duplicate of #11152.

@DanielRosenwasser DanielRosenwasser added the Duplicate An existing issue was already created label Jun 19, 2017
@seansfkelley
Copy link
Author

Certainly it's very closely related, but I think it's possibly different, since the type inference in my example does work as expected simply by changing the way the type is defined. It seems plausible that a fix to #11152 would also fix this, but I don't know enough about the compiler to state that for sure nor to definitively declare this as a duplicate.

@mhegazy
Copy link
Contributor

mhegazy commented Aug 17, 2017

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

@mhegazy mhegazy closed this as completed Aug 17, 2017
@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
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants