-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
TypeScript Version: 3.8.0-dev.20191116
Search Terms:
rest parameter, spread, tuple type, generics, conditional types
Code
https://github.com/BTOdell/typescript-tuple-rest-spread-bug
This issue was discovered when implementing a type-safe event emitter class. I've produced a minimum reproducible example at the GitHub link above as well as in a Playground link below.
index.tsdefines an unimplementedEventEmitterthat includes 4 functions which should be equivalent (except for theeventNameparameter).test.tsconsumes theEventEmitterclass and calls the various functions to test type-safety.
An Events interface is used to define the supported events by mapping the event name to a tuple type for the parameters of the event listener.
This interface is passed through a generic parameter E in the Test class and then passed through a generic parameter E in the EventEmitter class.
Expected behavior:
A listener function should be able to define 1 parameter even if the caller might pass 2 parameters. The listener will then only have access to the first parameter passed. This is how JavaScript normally behaves.
Actual behavior:
The unexpected behavior occurs on lines 29 and 33 (in test.ts) and only occurs when the Events interface type has to pass through 2 generic class parameters.
If line 14 is uncommented, and line 13 is commented then all unexpected behavior is resolved.
Error:(29, 47) TS2345: Argument of type '(b: boolean) => void' is not assignable to parameter of type '(...args: Args<E["multiArray"]>) => any'.
Types of parameters 'b' and 'args' are incompatible.
Type 'Args<E["multiArray"]>' is not assignable to type '[boolean]'.
Type 'E["multiArray"] | [E["multiArray"]]' is not assignable to type '[boolean]'.
Type 'any[] & E["multiArray"]' is not assignable to type '[boolean]'.
Types of property 'length' are incompatible.
Type '2' is not assignable to type '1'.
Type '[boolean, boolean]' is not assignable to type '[boolean]'.
Types of property 'length' are incompatible.
Type '2' is not assignable to type '1'.
It seems like the tuple types [boolean, boolean] and [boolean] are not being treated like they're being spread as a rest parameter in a function. Could the context information be getting lost due to jumping through multiple generic parameters?
Playground Link:
Playground link