Repository: TypeScript
Issue: type inference breaks with composition function using extend on generic arguments
Labels: Needs Investigation

# Bug Report

_Type inference breaks with composition function using extend on generic arguments_. I came across this issue while trying to implement composition for type guard functions [see](https://gist.github.com/safareli/8e480d72f7e2665b6030b9a08fe93f40).  it worked mostly but in some cases was getting strange type error demonstrated [here](https://gist.github.com/safareli/73e833ca2dff84806f79e935b4b7e9c2), then I tried to change type guards with functions and the issue has persisted. Meaning that it's more general issue and not specific to type guards.

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms
type guard composition extend inference

### 🕗 Version & Regression Information

Tested on ts@4.0-4.4 and all the versions have this issue

### ⏯ Playground Link

 
[Playground link with relevant code](https://www.typescriptlang.org/play?ts=4.3.2#code/C4TwDgpgBAYgrgOwMYB4CSCx2AGigeWy2AD4oBeKACgDcBDAGzggC4oNiBKCsw4YgNwAoIUgD2CAM7AoAMwZiA7hXR58UCAA9gEBABNJ7NQCYN23QYIkhUarLbxkqqzgDmDxKnwmSnD07QfHhtbagBLNjQ-AlNyMlcqWSowzk4RcSkZMDDICihnfGtbZMi8e1hPVULo9TiQ2ySUkSFQXIBBACEAYTzOqAAfKAAiLqGW8Gg+yiG2oYHhjrG9CCQGOgAnaAzpKDoAIzY+wcRl2TCECD0hZdWNrYkdsMkO-1ROrpwhxesbtc25TzAMISKAIMTAACq+ggZwuehQABUSMlMNg2Aj5icYedLtEEc1tjIDgs5pRspAqPVdnscFSAPR0qDnWQQTZ6KCtaBPFj0xnyJQoXmhI5QLGwy5CvAisU49koAC0ivlUAAFqyuYZWesxOsoAADOCnWV6qCSFVwMQMdl7aCbAC2YhoEtCUAZUDwXyGRVCbqocleKGl0PFeilHUxwdl3tsbrw7gqTiDRrhHu+QuijlQADoc9G5ApFFQwZDIymmc80i63S6a7WoAA-RtCm1IOhwSTQMSyJnIHUrYAMEA9llsjkTKCuCDAIEIVwclVPDTrbXrHlVxlQNrrVxwO26GRdse5ADkmcD3VTXuP5dB4N2kkkYVcCH2DGgwDEUDAGzoe50usPTkoFPSok2xMtPRIY8syFWwEXHY8wJDa9F2Le9H2fV930-IDEO6aDYNCeCTxlOEUMMNC6AfJ8Xz2N8ORwhD3mgqhjAAZgAFgAVkrUIhTCbs0FNSAkAEocgI2Hc9wQYBDDCGRFDCBgGCgRQdQAazkHE1x9PkC3PCNk0uHBOk+b4i3BKEjNDcsOm4WwhErZo3QAOXwBEAFE2AE1ToEUdUGNFDtbxLazVPklUxGwCddFZMIkF2bdd33XZlNUqKrSgG0oAAK3bGRxR5N1fjuAFkCBEFiys8DLhRYhDnDY5S1xBqRFc9yvKy8EVSgQCF0MNT1k0vKdnFUQHhkfYEAQABGBq8nJCAqH2PAquavQ0kJalpuMeayRyJaVvzJQLNCmrQzW6zUjaxk3M8uRLQLc45wYHFDHEO1sle2cv21J1DGAFU6BkPUnheBM3gvSCTUXKiaKwwLQeeXaIfPS8SBNa4Vj+e5MlslGz1Mkkfmx0qtroJAkAgMBgDQZG2CoJA1SQdSAyJyDuDiWwaDEMIrgpqmabpjpjGSCshAF6naeRsWRbSIA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
type Func<Input, Output> = (value: Input) => Output;

const flow =<I, O extends I, O2 extends O>
  (f: Func<I, O>,g: Func<O, O2>): Func<I, O2> =>
    (i: I): O2 => g(f(i))

const pipe = <I, O>
  (i: I, f: Func<I,O>): O =>
    f(i)


type ABC = AB | "C"
type AB = "A" | "B"
declare const ab: AB | undefined
declare const isB: Func<ABC,"B">
declare function notUndefined<T>(input: T | undefined): T


const b: "B" = pipe(
    ab,
    // infered type is:
    // flow<
    //   AB | undefined
    // , AB | undefined <---- here is error `udefined` shuold be removed
    // , "B">
    // ( f: Func<AB | undefined, AB | undefined>
    // , g: Func<AB | undefined, "B">
    // ): Func<...>
    flow(notUndefined, isB)
    //                 ~~~
    // because of incorectly infered type getting this error:
    //  Argument of type 'Func<ABC, "B">' is not assignable to parameter of type 'Func<AB | undefined, "B">'.
    //   Type 'AB | undefined' is not assignable to type 'ABC'.
    //     Type 'undefined' is not assignable to type 'ABC'.(2345)
    
    // if I specify type arguments it will work fine:
    // flow<AB | undefined,AB,"B">(notUndefined, isB)   
)
 


// NOTE: if we were to use notUndefined without generic argument all would be just fine:
// declare function notUndefined(input: AB | undefined): AB

// NOTE: both of this work just fine
const abnn1: AB = pipe(ab, notUndefined)
const abnn2: AB = pipe(ab, flow(notUndefined,notUndefined))

// NOTE following lines compiling proves that `isB: Func<ABC,"B">` is asignable to `isB2: Func<AB, "B">` 
declare const isB2: Func<AB, "B">
declare const acceptIsB2: (check: Func<AB, "B">) =>  void
acceptIsB2(isB)
acceptIsB2(isB2)
```

### 🙁 Actual behavior
as shown in code snippet type is inferred incorrectly and I'm getting compiler error .

### 🙂 Expected behavior
type should be inferred correctly.