microsoft / microsoft/TypeScript
type inference breaks with composition function using extend on generic arguments
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.4k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 117
Description
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. it worked mostly but in some cases was getting strange type error demonstrated here, 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.
🔎 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
💻 Code
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the linked TypeScript Playground repro and comparing flow(notUndefined, isB) with the explicitly supplied type arguments. Trace how generic arguments are inferred for the composition function. Done means the sample infers the intermediate type without including undefined and compiles with the expected "B" result.
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
- 45/100