Skip to content

fix(pipe): replace rest parameters overload#3945

Merged
benlesh merged 15 commits intoReactiveX:masterfrom
cartant:issue-3841
Jul 26, 2018
Merged

fix(pipe): replace rest parameters overload#3945
benlesh merged 15 commits intoReactiveX:masterfrom
cartant:issue-3841

Conversation

@cartant
Copy link
Copy Markdown
Collaborator

@cartant cartant commented Jul 24, 2018

Description:

IMPORTANT: This PR depends upon the dtslint additions in #3944.


WARNING: This PR uncovered several typing problems in the test suite, so it's likely that it will also uncover typing problems in user code that were previously hidden. Said problems in the test suite could have been hidden for a number of reasons:

  • for a long time, the test suite was not type checked;
  • the initial rest parameters signature could have hidden them; or
  • the rest parameters signature introduced in fix(Observable): Update typings of pipe #3789 would have continued to hide them.

It fixes a problem that was introduced in this commit. Prior to that commit, the pipe overload signature for more than 9 arguments looked like this:

pipe<R>(...operations: OperatorFunction<T, R>[]): Observable<R>;

Which is incorrect, as consecutive arguments have to have matching output/input types - every OperatorFunction passed cannot accept a T and return an R.

Unfortunately, fixing that by changing the signature to the following introduced another problem:

pipe<R>(...operations: OperatorFunction<any, any>[]): Observable<R>;

With that signature, any usage with 9 or fewer arguments that does not match a signature due to type errors will now match the rest parameters signature. So strong typing is subverted and that's the problem highlighted in #3841.

In a comment in this TypeScript issue, Anders Hejlsberg has pointed out the output/input relationship between arguments means that the overloads cannot be avoided. So to restore strong typing, this PR replaces the rest parameters overload signature with a signature that also includes the preceding 9 type-parameter-specified arguments, like this:

pipe<A, B, C, D, E, F, G, H, I, R>(
  op1: OperatorFunction<T, A>,
  op2: OperatorFunction<A, B>,
  op3: OperatorFunction<B, C>,
  op4: OperatorFunction<C, D>,
  op5: OperatorFunction<D, E>,
  op6: OperatorFunction<E, F>,
  op7: OperatorFunction<F, G>,
  op8: OperatorFunction<G, H>,
  op9: OperatorFunction<H, I>,
  ...operations: OperatorFunction<any, any>[]
): Observable<R>;

The effect of this is that it will no longer be possible to specify a single R type parameter for pipe calls that involve more than 9 arguments. Instead, an assertion would need to be used like this:

const result = of("T").pipe(
    mapTo("A"),
    mapTo("B"),
    mapTo("C"),
    mapTo("D"),
    mapTo("E"),
    mapTo("F"),
    mapTo("G"),
    mapTo("H"),
    mapTo("I"),
    mapTo("R")
) as Observable<"R">; // Otherwise inferred to be Observable<{}>

This PR also adds dtslint tests for pipe and the static pipe utility function that include expectations for type inference and errors.

Related issue (if exists): #3841

Loading
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants