-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Type incorrectly inferred as "string" rather than String Literal #22038
Comments
Could you provide an example that includes an explicit type argument? Type inference is probably not powerful enough to get you a good type here. |
This bites me quite often too, and it is quite annoying. function needALiteral(thing: 'THING') { }
const FOO = { thing: 'THING' };
needALiteral(FOO.thing); // ERROR: string is not assignable to 'THING' Today, the only way to tell Typescript that 'THING' is really meant to be just a literal, is by duplicating it: function needALiteral(thing: 'THING') { }
const FOO = { thing: 'THING' as 'THING' };
needALiteral(FOO.thing); // Happy compiler Now, if there is a typo on the first 'THING', it's going to be fun to debug the runtime error. I wish there was a more compact way to express that, also avoiding the chance of typos causing bugs. |
@rubenlg It's generally a good idea to provide a type to an object literal: interface I { thing: 'THING' };
const FOO: I = { thing: 'THING' }; That way we give you string literal types and also detect excess properties. |
@andy-ms I totally agree, and I always do when it's possible/reasonable, but there are situations when it's not. Here is one example: export interface Foo {
x: 'FOO' | 'BAR';
y: number;
z: {},
}
// private to this module
const commonPart = {
x: 'FOO',
y: 2,
};
export const case1: Foo = {
...commonPart,
z: whatever,
};
export const case2: Foo = {
...commonPart,
z: somethingelse,
}; In this case, you don't want to type commonPart. |
Would it help if |
Totally. Detecting that mistake at compile time would be great. |
OK, created #22150 |
I'm running into the same issue. Minimal test case: const x = { a: 'abc' };
const y: { a: 'abc' | 'def' } = x; // type error: string not assignable to 'abc' | 'def'
const x2 = { a: 'abc' as 'abc' };
const y2: { a: 'abc' | 'def' } = x2; // typechecks Try it in the TypeScript Playground Am I correct in understanding that the reason for this issue is that TypeScript has no way of knowing I don't want to do |
Duplicate of #20271 |
@mhegazy you closed this as a duplicate of another bug that's also closed. Do I understand correctly that the Typescript team has no intention to fix this problem? |
@rubenlg the specified behavior in this issue is the intended behavior. Some of the repros here represent a non-ideal user experience but there's no sound proposal on the table that is immediately actionable. |
For those who are stuck, as a last resort you can use this workaround: function stringLit<a>(val: a): a {
return val;
} And then you use it like this: stringLit<"lastName">("lastName") This is better than typing |
That's a great trick @benny-medflyt. Note that it works with numbers too, so you could call it |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
Tested with:
TypeScript 2.6.2
TypeScript 2.7.2
Attached is an example where a string literal (
"lastName"
) is being inferred as"string"
rather than as the string literal"lastName"
. Adding a type assertion ("lastName" as any
) causes compilation to succeed.The text was updated successfully, but these errors were encountered: