You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
classVar{id: numbername: stringstaticcounter=0constructor(name: string){this.id=Var.counter++this.name=name}}functionv(strs: TemplateStringsArray): Var{const[name]=strsreturnnewVar(name)}typeLogical<T>=Var|{[PinkeyofT]: Logical<T[P]>}typeList<T>=null|{head: T;tail: List<T>}functioncons<T>(head: Logical<T>,tail: Logical<List<T>>): Logical<List<T>>{return{ head, tail }}functiontest(element: Logical<string>,list: Logical<List<string>>): void{}// This is Ok.test("a",cons<string>(v`element`,v`tail`))// But this is not Ok.test("a",cons(v`element`,v`tail`))
🙁 Actual behavior
When I do not write the annotation for cons, an error occured:
Argument of type 'Logical<List<{ id: { toString: ...; toFixed: ...; toExponential: ...; toPrecision: ...; valueOf: ...; toLocaleString: ...; }; name: { toString: ...; charAt: ...; charCodeAt: ...; concat: ...; indexOf: ...; lastIndexOf: ...; ... 43 more ...; at: ...; }; }>>' is not assignable to parameter of type 'Logical<List<string>>'.
Type '{ head: Logical<{ id: { toString: ...; toFixed: ...; toExponential: ...; toPrecision: ...; valueOf: ...; toLocaleString: ...; }; name: { toString: ...; charAt: ...; charCodeAt: ...; concat: ...; indexOf: ...; lastIndexOf: ...; ... 43 more ...; at: ...; }; }>; tail: Logical<...>; }' is not assignable to type 'Logical<List<string>>'.
Type '{ head: Logical<{ id: { toString: ...; toFixed: ...; toExponential: ...; toPrecision: ...; valueOf: ...; toLocaleString: ...; }; name: { toString: ...; charAt: ...; charCodeAt: ...; concat: ...; indexOf: ...; lastIndexOf: ...; ... 43 more ...; at: ...; }; }>; tail: Logical<...>; }' is not assignable to type '{ head: Logical<string>; tail: Logical<List<string>>; }'.
Types of property 'head' are incompatible.
Type 'Logical<{ id: { toString: ...; toFixed: ...; toExponential: ...; toPrecision: ...; valueOf: ...; toLocaleString: ...; }; name: { toString: ...; charAt: ...; charCodeAt: ...; concat: ...; indexOf: ...; lastIndexOf: ...; ... 43 more ...; at: ...; }; }>' is not assignable to type 'Logical<string>'.
Type '{ id: Logical<{ toString: unknown; toFixed: unknown; toExponential: unknown; toPrecision: unknown; valueOf: unknown; toLocaleString: unknown; }>; name: Logical<{ toString: unknown; charAt: unknown; charCodeAt: unknown; concat: unknown; indexOf: unknown; lastIndexOf: unknown; localeCompare: unknown; ... 42 more ...; ...' is not assignable to type 'Logical<string>'.
Type '{ id: Logical<{ toString: unknown; toFixed: unknown; toExponential: unknown; toPrecision: unknown; valueOf: unknown; toLocaleString: unknown; }>; name: Logical<{ toString: unknown; charAt: unknown; charCodeAt: unknown; concat: unknown; indexOf: unknown; lastIndexOf: unknown; localeCompare: unknown; ... 42 more ...; ...' is not assignable to type 'Var'.
Types of property 'id' are incompatible.
Type 'Logical<{ toString: unknown; toFixed: unknown; toExponential: unknown; toPrecision: unknown; valueOf: unknown; toLocaleString: unknown; }>' is not assignable to type 'number'.
Type 'Var' is not assignable to type 'number'.
37 test("a", cons(v`element`, v`tail`))
~~~~~~~~~~~~~~~~~~~~~~~~~
🙂 Expected behavior
I expect type checker inference the type annotation for me, so I can write:
test("a",cons(v`element`,v`tail`))
Instead of:
test("a",cons<string>(v`element`,v`tail`))
The text was updated successfully, but these errors were encountered:
There are two problems here, both of which might be bugs but I’m not confident that either is. It’s easiest to demonstrate minimal versions of each.
The first is that head and/or tail is acting as an inference source for T in cons. You might expect that neither would be, since each matches the Var constituent of Logical, we shouldn’t have to try to infer to the { [P in keyof T]: Logical<T[P]> } constituent at all. If this were the case, the only remaining inference target would be the return type Logical<List<T>> which would match up with the contextual type Logical<List<string>> from test. However, we clearly are trying to infer from head and/or tail to { [P in keyof T]: Logical<T[P]> } (and we succeed at that), so the inference is fixed before the weaker return type inference can play a role. You can see a simplified example of this happening here.
The second problem is why the error messages are so awful: we are forming reverse mapped types for the properties of primitives. A generic mapped type applied to a primitive returns just the primitive, so you might expect a reverse mapped type inferred from a primitive to just be the primitive as well. This is a bit hard to reason about, as it's hard to come up with a meaningful mapped type that a primitive would be assignable to in the first place, but there is clearly an asymmetry. You can see it in action here.
name: Bug
about: Create a report to help us improve TypeScript
title: Typescript fail to unify type variables
labels: ''
assignees: ''
Bug Report
🔎 Search Terms
unify type variables
,unification
,type inference
.🕗 Version & Regression Information
This is the behavior in every version I tried, and I reviewed the FAQ for entries about
Generics
.⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
When I do not write the annotation for
cons
, an error occured:🙂 Expected behavior
I expect type checker inference the type annotation for me, so I can write:
Instead of:
The text was updated successfully, but these errors were encountered: