-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Literal String Union Autocomplete #29729
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
From the compiler's point of view, this is just a very fancy way of writing You could write something like this: Naturally this doesn't stop you from writing |
Why not improve the compiler to keep more metadata around? |
It may accomplish the same behavior, but that's not intuitive to me at all. I doubt I could have gotten there on my own, and I know I would have trouble explaining it to someone newly coming to TS from JS. |
It would be great to have this built in, although understand it may be difficult to implement on the compiler. In the meantime, a generic workaround based on @RyanCavanaugh's solution might help: type LiteralUnion<T extends U, U = string> = T | (U & { zz_IGNORE_ME?: never })
type Color = LiteralUnion<'red' | 'black'>
var c: Color = 'red' // Has intellisense
var d: Color = 'any-string' // Any string is OK
var d: Color = { zz_IGNORE_ME: '' } // { zz_IGNORE_ME } placeholder is at the bottom of intellisense list and errors because of never
type N = LiteralUnion<1 | 2, number> // Works with numbers too |
Would be great if this could be implemented. It has the potential to improve even core Node.js APIs. The hash.digest |
Hey Guys type LiteralUnion<T extends U, U = string> = T | (U & {});
let x: LiteralUnion<"hello" | "world">;
x = "hey"; While this code is perfectly valid, "hello", and "world" are still showing up in the autocompletion. |
I noticed a problem with type guards using this hack: type LiteralUnion<T extends U, U = string> = T | (U & {});
function something(arg: LiteralUnion<'a' | 'b'>): 'a' {
if (arg === 'a') {
return arg; // Type '(string & {}) | "a"' is not assignable to type '"a"'
}
} Is there a way around this? |
I think I might have found a solution: Use a type like my type LiteralUnion<T extends U, U = string> = T | (U & {});
type UnpackedLiteralUnion<T> = T extends LiteralUnion<any, infer U> ? U : never
function something(arg: LiteralUnion<'a' | 'b'>): 'a' {
let unpackedArg = arg as UnpackedLiteralUnion<typeof arg>;
if (unpackedArg === "a") {
return unpackedArg;
}
else {
return "a";
}
} |
@manuth Your solution not work for me can you know why ? |
@AhmedElywa it's because you're using Here's the longer explanation: let x: (string & never); // x has type `never`
let y: number | (string & never); // y has type `number`
let z: ("Hello" | "world") | (string & never); // z has type `"Hello" | "world"` In order to get the solution to work you have to use How the solution workslet a: ("hello" | "world") | string; In this snippet let a: ("hello" | "world") | (string & {}); In this code-snippet Hope this helped you understanding. |
For those interested, there is a workaround for this called |
Is there a way to use this hack with the object key? |
yes, as a workaround you can use |
@mfulton26 it does not seem to work even with this helper. Adding both unions into a single string literal causes the whole thing to become just string. |
it works if you move the template literal type into |
If I'm understanding correctly, the reason the suggested solutions work is that a union of a primitive type and some variation of an empty object produces the wrapper/boxed object type corresponding to that primitive. For example, This prevents the union from getting reduced to the wider type, as the compiler will not reduce a literal to an object type. However, assignability is preserved, so we're still able to assign an arbitrary string value in this case. type Str1 = 'foo' | string;
// ^? string
type Str2 = 'bar' | String;
// ^? String | 'bar'
let a: Str2;
a = 'foo'; // 'foo' suggested via autocomplete
a = 'bar'; // arbitrary string does not error Is this the correct interpretation or am I making some incorrect assumptions along the way? |
Autocomplete works for literal string unions, but adding a union of
string
negates autocomplete entirely. This has been brought up before but I believe there is enough value in this feature to be reconsidered.My use case is to have a union of string literals for several colors, but also allow hex codes without having to add 16.7 million string literals.
TypeScript Version: 3.4.0-dev.20190202
Search Terms: Literal string union autocomplete
Code
Expected behavior:
Actual behavior:
Playground Link: https://stackblitz.com/edit/typescript-bwyyab
Related Issues: #12687 #13614
The text was updated successfully, but these errors were encountered: