Repository: TypeScript
Issue: Typescript fail to unify type variables
Labels: Needs Investigation

---
name: Bug
about: Create a report to help us improve TypeScript
title: Typescript fail to unify type variables
labels: ''
assignees: '' 
---

# Bug Report

### 🔎 Search Terms

<!--
  What search terms did you use when trying to find an existing bug report?
  List them here so people in the future can find this one more easily.
-->

`unify type variables`, `unification`, `type inference`.

### 🕗 Version & Regression Information

<!-- When did you start seeing this bug occur?

"Bugs" that have existed in TS for a long time are very likely to be FAQs; refer to
  https://github.com/Microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs

If possible, please try testing the nightly version of TS to see if it's already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly

Note: The TypeScript Playground can be used to try older versions of TypeScript.

Please keep and fill in the line that best applies:
-->

This is the behavior in every version I tried, and I reviewed the FAQ for entries about `Generics`.

### ⏯ Playground Link

<!--
  A link to a TypeScript Playground "Share" link which shows this behavior

  The TypeScript Workbench can be used for more complex setups, try
  https://www.typescriptlang.org/dev/bug-workbench/

  As a last resort, you can link to a repo, but these will be slower for us to investigate.
-->
[Playground link with relevant code](https://www.typescriptlang.org/play?#code/MYGwhgzhAEBqYCdoG8BQ1oEsAmAuaAdgK4C2ARgKYLqFgkX4QAuCmBA5qjc2E5sNGAB7IgSZVoAXmgAGLhmEFmCIsCZCEACgJ0G0ZW3YBKFDQxMAFpggA6HFLiIbw0eIQBqd2eiXrNnfQOARQ0AL6o4agAZqJqmEIE0ABumsoQ+AAqFCQADuDiAMoshhAAgggIYACeRvjwSGgKCczQANrBALoOaTQIFExECIkEFADujlrBRhFcTFU5FNAAMkLs-GAgADwZAHwO9dAAPihtAApYiQDWFFVCUdAZHfgra8Ab262nHXuRcwvL1iY2z20mIIBARxOFgoYDwDwA3D4wJgQM9AcDoJEYgQ4glBM1gZoaNDYc9VustrsADQ0JjI1HLclvLZLdG7HaoWqM17vVnMYF7RrQPoDIZQmHYKlIlGYmbRWJ8PHiZiaCggbIUMRknlbAwcHZSkCA7UUzZ8oF69g7HZcpJCexoOUAeidDysMGs0AA8pcbKhlUxNAAiMBBqWKCCbS07TRJAAGao1YjjUvjdJRcaM01QLugACEiEwfO6sDACEIiz6-QHg6Hw81Ywn1fRk6m4+mQJnpkA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
``` typescript
class Var {
  id: number
  name: string

  static counter = 0

  constructor(name: string) {
    this.id = Var.counter++
    this.name = name
  }
}

function v(strs: TemplateStringsArray): Var {
  const [name] = strs
  return new Var(name)
}

type Logical<T> = Var | { [P in keyof T]: Logical<T[P]> }

type List<T> = null | { head: T; tail: List<T> }

function cons<T>(head: Logical<T>, tail: Logical<List<T>>): Logical<List<T>> {
  return { head, tail }
}

function test(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

<!-- What happened, and why it was wrong -->

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

<!-- What you expected to happen instead, and why -->

I expect type checker inference the type annotation for me, so I can write:

``` typescript
test("a", cons(v`element`, v`tail`))
```

Instead of:

``` typescript
test("a", cons<string>(v`element`, v`tail`))
```