Repository: effector/effector
Pull request #414 (2020-11-04 18:16:55)

Fix event type, add type tests


Patch:
diff --git a/packages/effector/index.d.ts b/packages/effector/index.d.ts
index cc92919c..20bd0985 100644
--- a/packages/effector/index.d.ts
+++ b/packages/effector/index.d.ts
@@ -108,7 +108,7 @@ export type CompositeName = {
 
 export interface Event<Payload> extends Unit<Payload> {
   (payload: Payload): Payload
-  (this: Payload extends void ? void : `Error: Expected 1 argument, but got 0`): void
+  (this: Payload extends void ? void : `Error: Expected 1 argument, but got 0`, payload?: Payload): void
   watch(watcher: (payload: Payload) => any): Subscription
   map<T>(fn: (payload: Payload) => T): Event<T>
   filter<T extends Payload>(config: {


Test patch:
diff --git a/src/types/__tests__/effector/effect.test.js b/src/types/__tests__/effector/effect.test.js
index 4ca9aed5..a7895f93 100644
--- a/src/types/__tests__/effector/effect.test.js
+++ b/src/types/__tests__/effector/effect.test.js
@@ -487,6 +487,9 @@ describe('#filterMap', () => {
       "
       --typescript--
       Type 'Event<number>' is not assignable to type 'Event<number | void>'.
+        Types of parameters 'payload' and 'payload' are incompatible.
+          Type 'number | void' is not assignable to type 'number'.
+            Type 'void' is not assignable to type 'number'.
 
       --flow--
       no errors
diff --git a/src/types/__tests__/effector/event.test.js b/src/types/__tests__/effector/event.test.js
index ba81cc55..51f62231 100644
--- a/src/types/__tests__/effector/event.test.js
+++ b/src/types/__tests__/effector/event.test.js
@@ -222,3 +222,79 @@ test('call event without params (never)', () => {
     "
   `)
 })
+test('assign event to a function (should pass)', () => {
+  const fn1: (event: number) => number = createEvent<number>()
+  expect(typecheck).toMatchInlineSnapshot(`
+    "
+    --typescript--
+    no errors
+
+    --flow--
+    no errors
+    "
+  `)
+})
+test('assign event to a function (should fail)', () => {
+  /*:: type unknown = any; */
+  const fn1: (event: number) => unknown = createEvent<string>()
+  expect(typecheck).toMatchInlineSnapshot(`
+    "
+    --typescript--
+    Type 'Event<string>' is not assignable to type '(event: number) => unknown'.
+      Types of parameters 'payload' and 'event' are incompatible.
+        Type 'number' is not assignable to type 'string'.
+
+    --flow--
+    Cannot assign 'createEvent<...>()' to 'fn1'
+      const fn1: (event: number) => unknown = createEvent<string>()
+                                              ^^^^^^^^^^^^^^^^^^^^^
+      string [1] is incompatible with number [2] in the first argument. [incompatible-type]
+          const fn1: (event: number) => unknown = createEvent<string>()
+                                                          [1] ^^^^^^
+          const fn1: (event: number) => unknown = createEvent<string>()
+                         [2] ^^^^^^
+    "
+  `)
+})
+test('createEvent edge case', () => {
+  // Default type is inferred
+  const fn: (event: number) => number = createEvent()
+  expect(typecheck).toMatchInlineSnapshot(`
+    "
+    --typescript--
+    no errors
+
+    --flow--
+    no errors
+    "
+  `)
+})
+test('void function edge case (should fail)', () => {
+  /*:: type unknown = any; */
+  // Typed event is assignable to a void function
+  const voidFn: () => void = createEvent<number>()
+  expect(typecheck).toMatchInlineSnapshot(`
+    "
+    --typescript--
+    no errors
+
+    --flow--
+    Cannot assign 'createEvent<...>()' to 'voidFn'
+      const voidFn: () => void = createEvent<number>()
+                                 ^^^^^^^^^^^^^^^^^^^^^
+      function type [1] requires another argument from function type [2]. [incompatible-type]
+          (payload: Payload): Payload;
+      [1] ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+          const voidFn: () => void = createEvent<number>()
+                    [2] ^^^^^^^^^^
+    Cannot assign 'createEvent<...>()' to 'voidFn'
+      const voidFn: () => void = createEvent<number>()
+                                 ^^^^^^^^^^^^^^^^^^^^^
+      number [1] is incompatible with undefined [2] in the return value. [incompatible-type]
+          const voidFn: () => void = createEvent<number>()
+                                             [1] ^^^^^^
+          const voidFn: () => void = createEvent<number>()
+                          [2] ^^^^
+    "
+  `)
+})