microsoft / microsoft/TypeScript

Overload causes generic function to loose type specificity

Open
#52,381 1 comment 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Needs Investigation
Dominant language
Go
Stars
111k
Forks
14.4k
Avg merge
1d 19h
Merged PRs (30d)
117

Description

Bug Report

🔎 Search Terms

generic overloaded function type narrowing

🕗 Version & Regression Information
  • This is the behavior in every version I tried (4.8, 4.9)
⏯ Playground Link

https://www.typescriptlang.org/play?#code/FASwdgLgpgTgZgQwMZQAQEFUG9itQgLlQEYBuYAX2FElkRVQCFUoAPaMAEwGcNtdUAIyIAmclRrR4yNAHUYCAA6LYxADwAVFuyhde6AHz88ANwQAbAK5QiG8dXBT6chctgjN2jjwxGcpi2tbe2A4SzAkCBAAezBUcIB3V082b30DAAokpRVOInkc1U0DAEpbUPDImLjE5K1U3R9DLNdc-Nb3YrLUDQqIqNj4sGzFFJ09XxbCvNQCtxh1DSMAH1mOmA8l7q1-VBgoCEsYOJHcgDozKygQpFjuCCEiZgBebHwiYgAaR9QRVApyLcwPdUKcoDM5ioFmpGEZXlhUJcgkJ-tQgSDoPdiKhXrUlFM3JwSqRUAB6UmoTEQYhPVAZW4wfaRErAdEPKl-V4ABRg0QAtiBuFAzvtuNFzCYoATciUzhAABa6DJ4xTEskUjlEHn8wVQNSGOnceXRSzmThCNDagVCmGlVl3dlQe4AZhxqAA2mDOABdM58-EqtXkylOiDOojod3ew3G03mwRoRhRllAA

💻 Code

interface A {
  a: 1;
}

interface B extends A {
  b: 2;
}

interface Wrapper1<T extends A> {
  value: T;
}

interface Wrapper2<T extends A> {
  value: T;
}

function unwrap<T extends A>(wrapped: Wrapper1<T>): T
function unwrap<T extends A>(wrapped: Wrapper2<T>): T // Comment out this line, and types will become inferred correctly
function unwrap<T extends A>(wrapped: Wrapper1<T> | Wrapper2<T>): T {
  return wrapped.value;
}

const b: B = { a: 1, b: 2 };
const wrapped: Wrapper1<B> = { value: b }

const test1 = unwrap(wrapped); // test1: B (correct)
const test2 = Promise.resolve(wrapped).then(unwrap); // test2: Promise<A> (should be Promise<B>)
const test3 = [wrapped].map(unwrap); // test3: A[] (should be B[])
🙁 Actual behavior

In test2 and test3, the generic type of the overloaded function unwrap looses it's specificity. The types can be narrowed to Promise<B> and B[] respectively, but actually it is inferred as Promise<A> and A[] respectively. Removing the one of the overloads of the function unwrap (so it is no longer overloaded) will resolve the problem.

🙂 Expected behavior

As explained above, the inferred types of test2 and test3 should be inferred as Promise<B> and B[] respectively.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked TypeScript Playground reproduction and compare inference for test1, test2, and test3 when both overloads are present. Trace the generic overload and type-inference behavior involved; done means test2 is Promise and test3 is B[] without removing an overload.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.