question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Incorrect assignability check when using Extract (TS2322)

See original GitHub issue

Bug Report

🔎 Search Terms

extract assignable TS2322

🕗 Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ for entries about Generics, Assignability, and Extract.

Tested with 4.2.3, 4.3.5, 4.4.4, and 4.5.0-dev.20211018.

In 4.1.5, the example using a type alias also fails. Version 4.2 introduced Smarter Type Alias Preservation, which may explain why that example passes starting from 4.2.x.

⏯ Playground Link

Playground link with relevant code

💻 Code

I have attempted to minimize this example as much as possible. The use of Extract to define a field type appears to be significant.

type A<T> = {
    val: Extract<number | string, T>;
};
type A_number = A<number>;

function f1(x: A_number): A<number| string> {
    // Passes type checking.
    return x;
}

function f2(x: A<number>): A<number | string> {
    // Fails type checking with error TS2322:
    // Type 'A<number>' is not assignable to type 'A<string | number>'.
    //   Type 'string | number' is not assignable to type 'number'.
    //     Type 'string' is not assignable to type 'number'.
    return x;
}

🙁 Actual behavior

The type checker reports error TS2322: A<number> is not assignable to type A<string | number> because string | number is not assignable to number. It appears to be checking assignability of a field in the wrong direction, because the assignability check should be whether number is assignable to string | number.

Using a type alias for A<number> does not produce the same error. I was also not able to reproduce this error without using Extract to define a field type.

🙂 Expected behavior

The type A<number> should be assignable to type A<string | number> because it is a simple object type and number is assignable to string | number.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
tjjfvicommented, Oct 18, 2021

It thinks that A is invariant; this also fails:

function f2(x: A<number | string>): A<number> {
    return x;
}
Type 'A<string | number>' is not assignable to type 'A<number>'.
  Types of property 'val' are incompatible.
    Type 'string | number' is not assignable to type 'number'.
      Type 'string' is not assignable to type 'number'.

This makes sense for general conditional types (consider type X<T> = {} extends T ? 1 : 2; X<{}> isn’t assignable to or from X<{ x: string }>); Extract is just a special case where it’s only covariant.

The real bug here afaict is that TS is doing a variance check here instead of doing structural comparison; the variance measure should probably be tagged with VarianceFlags.Unreliable (which means that variance checking may produce false negatives, but not false positives).

1reaction
fatcerberuscommented, Oct 18, 2021

Sorry, my mistake, I got Extract mixed up with Exclude. That said, the issue/bug appears to be that TS is measuring A<T> as contravariant for some reason:

Type 'A<number>' is not assignable to type 'A<string | number>'.
  Type 'string | number' is not assignable to type 'number'.

string | number indeed isn’t assignable to number, but this is going in the opposite direction relative to A. So for whatever reason it seems to think T is contravariant. 🤔

Read more comments on GitHub >

github_iconTop Results From Across the Web

TS2322: Invalid assignment error · Issue #33135 - GitHub
I don't know nor do I understand what causes the false behaviour on this particular assignment. Related Issues: ./.
Read more >
typescript | boolean' is not assignable to type 'undefined' happen
I don't know how to fix the property type, but you could work around the problem by using: if (value !== undefined) Object....
Read more >
type 'string' is not assignable to type 'number'.ts(2322) - You.com
Customize search with apps ... Type 'number' is not assignable to type 'string'. ts(2322) ... In order to resolve this problem, change ....
Read more >
Type {} is not assignable to ReactNode FIX - YouTube
In this video extract we fix the react native typescript error: Type {} is not assignable to ReactNode.
Read more >
TypeScript: Transforming optional properties to required ...
Here's a handy TypeScript generic for transforming a type with ... by extracting just that one property extends (read: is assignable to) the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found