-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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 generic not always inferred when part of union in nested object #19632
Comments
Looks similar to #19497 -- we get this a lot... |
I read through #19497 and I think I understand what's going on in that one but I don't think this is a duplicate. In #19497 as I understand it the issue is essentially about any time a pattern like declare function arr<T>(val: T): Array<T> // or any type similar to Container<T> occurs, In my mind that seems mostly unrelated to what is happening in my example. What seems so odd about my example and really makes me think it is a bug is the how the inference works correctly here: const directUnionSingle = direct("z") // inferred to be Record<"z", string>
const directUnionArray = direct(["z", "y"]) // inferred to be Record<"z" | "y", string> but that same pattern fails, but only partially fails, if they are nested inside of an object: const nestedUnionSingle = nestedUnion({fields: "z"}) // inferred to be Record<string, string>
const nestedUnionArray = nestedUnion({fields: ["z", "y"]}) // inferred to be Record<"z" | "y", string> |
@andy-ms Also more evidence that this is not a duplicate of #19497 is that all the examples in #19497 work if the generic type is constrained to extend string: 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 declare function arr<T extends string>(val: T): T[]
const y: "a"[] = arr("a"); // now works In my example the generic includes |
To narrow it down, the error is basically that this doesn't work: declare function f<A extends string>(a: { fields: A | A[] }): Record<A, string>
const r: Record<"z", string> = f({ fields: "z" }); Still seems like another case of #19497 and has the same workaround of |
declare function arr<T>(val: T): T[]
const y: "a"[] = arr("a"); // error as expected
declare function arr2<T>(val: T | T[]): T[]
const y2: "a"[] = arr2("a"); // error as expected
declare function arr3<T>(val: {fields: T}): T[]
const y3: "a"[] = arr3({fields: "a"}); // error as expected
declare function arr4<T>(val: {fields: T | T[]}): T[]
const y4: "a"[] = arr4({fields: "a"}); // error as expected
declare function arr5<T>(val: {fields: T | T[]}): T[]
const y5: "a"[] = arr5({fields: ["a"]}); // error as expected
declare function strarr<T extends string>(val: T): T[]
const s1: "a"[] = strarr("a"); // no error as expected
declare function strarr2<T extends string>(val: T | T[]): T[]
const s2: "a"[] = strarr2("a"); // no error as expected
declare function strarr3<T extends string>(val: {fields: T}): T[]
const s3: "a"[] = strarr3({fields: "a"}); // no error as expected
declare function strarr4<T extends string>(val: {fields: T | T[]}): T[]
const s4: "a"[] = strarr4({fields: "a"}); // *** unexpected error ***
declare function strarr5<T extends string>(val: {fields: T | T[]}): T[]
const s5: "a"[] = strarr5({fields: ["a"]}); // no error as expected If it is the same design limitation as #19497 then why do 4 of the 5 start working after adding |
Fixes microsoft#19632. The issue was isLiteralContextualType was only checking for type parameters that extended a literal base type at the top level. It was already recursively checking the constituents of unions and intersections but it did so using maybeTypeOfKind which only compared type flags matching literal or index. Also adds a test case that failed before this change and succeeds now.
Heads up I added a PR at #19684 that would fix this behavior if accepted. |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
TypeScript Version: Version 2.7.0-dev.20171031
Code
Expected behavior:
All 5 calls to
hasZField
compile without errorsActual behavior:
One call does not compile because it infers
A
to bestring
instead of"z"
Not a big deal just a quirk I came across and assume is a bug.
The text was updated successfully, but these errors were encountered: