Repository: effector/effector
Pull request #457 (2021-02-23 01:12:43)

Fix `split` edge cases


Patch:
diff --git a/packages/effector/index.d.ts b/packages/effector/index.d.ts
index c9c04889..2e0eaa30 100644
--- a/packages/effector/index.d.ts
+++ b/packages/effector/index.d.ts
@@ -493,16 +493,17 @@ export function createStoreObject<State>(
 
 export function split<
   S,
-  Match extends {[name: string]: ((payload: S) => boolean) | Store<boolean>}
+  Match extends {[name: string]: ((payload: S) => boolean) | Store<boolean>},
+  T extends Target = Target
 >(config: {
   source: Unit<S>
   match: Match
   cases: Partial<
     {
       [K in keyof Match]: Match[K] extends (p: any) => p is infer R
-        ? Unit<R>
-        : Unit<S>
-    } & {__: Unit<S>}
+      ? MultiTarget<T, R>
+      : MultiTarget<T, S>
+    } & {__: MultiTarget<T, S>}
   >
 }): void
 export function split<
@@ -516,19 +517,23 @@ export function split<
     ? Event<R>
     : Event<S>
 } & {__: Event<S>}>
-export function split<S, Match extends ((p: S) => keyof any)>(config: {
+export function split<
+  S,
+  K extends keyof any,
+  T extends Target = Target
+>(config: {
   source: Unit<S>
-  cases: ReturnType<Match> extends infer CaseSet
-    ? Partial<Record<(CaseSet extends string ? CaseSet : never) | '__', Unit<S>>>
-    : never
-  match: Match
+  match: (p: S) => K
+  cases: Partial<{[X in K]: MultiTarget<T, S>} & {__: MultiTarget<T, S>}>
 }): void
-export function split<S, Match extends Unit<keyof any>>(config: {
+export function split<
+  S,
+  K extends keyof any,
+  T extends Target = Target
+>(config: {
   source: Unit<S>
-  cases: Match extends Unit<infer CaseSet>
-    ? Partial<Record<(CaseSet extends string ? CaseSet : never) | '__', Unit<S>>>
-    : never
-  match: Match
+  match: Unit<K>
+  cases: Partial<{[X in K]: MultiTarget<T, S>} & {__: MultiTarget<T, S>}>
 }): void
 
 export function createApi<


Test patch:
diff --git a/src/types/__tests__/effector/split.test.ts b/src/types/__tests__/effector/split.test.ts
index 00ae8e1a..6b4f4e72 100644
--- a/src/types/__tests__/effector/split.test.ts
+++ b/src/types/__tests__/effector/split.test.ts
@@ -1,5 +1,5 @@
 /* eslint-disable no-unused-vars */
-import {createEvent, createStore, Event, split} from 'effector'
+import {createEvent, createStore, Event, guard, split} from 'effector'
 
 const typecheck = '{global}'
 
@@ -82,15 +82,15 @@ test('matcher store case mismatch (should fail)', () => {
   expect(typecheck).toMatchInlineSnapshot(`
     "
     No overload matches this call.
-      Overload 1 of 4, '(config: { source: Unit<number>; match: { [name: string]: Store<boolean> | ((payload: number) => boolean); }; cases: Partial<{ [x: string]: Unit<number>; } & { __: Unit<number>; }>; }): void', gave the following error.
+      Overload 1 of 4, '(config: { source: Unit<number>; match: { [name: string]: Store<boolean> | ((payload: number) => boolean); }; cases: Partial<{ [x: string]: Target; } & { __: Target; }>; }): void', gave the following error.
         Type 'Store<\\"a\\" | \\"c\\">' is not assignable to type '{ [name: string]: Store<boolean> | ((payload: number) => boolean); }'.
           Index signature is missing in type 'Store<\\"a\\" | \\"c\\">'.
-      Overload 2 of 4, '(config: { source: Unit<number>; cases: Partial<Record<string, Unit<number>>>; match: (p: number) => string | number | symbol; }): void', gave the following error.
-        Type 'Store<\\"a\\" | \\"c\\">' is not assignable to type '(p: number) => string | number | symbol'.
-          Type 'Store<\\"a\\" | \\"c\\">' provides no match for the signature '(p: number): string | number | symbol'.
-      Overload 3 of 4, '(config: { source: Unit<number>; cases: Partial<Record<\\"a\\" | \\"__\\" | \\"c\\", Unit<number>>>; match: Store<\\"a\\" | \\"c\\">; }): void', gave the following error.
-        Type '{ a: Event<number>; b: Event<number>; __: Event<number>; }' is not assignable to type 'Partial<Record<\\"a\\" | \\"__\\" | \\"c\\", Unit<number>>>'.
-          Object literal may only specify known properties, and 'b' does not exist in type 'Partial<Record<\\"a\\" | \\"__\\" | \\"c\\", Unit<number>>>'.
+      Overload 2 of 4, '(config: { source: Unit<number>; match: (p: number) => \\"a\\" | \\"b\\" | \\"__\\"; cases: Partial<{ a: Event<number>; b: Event<number>; __: Event<number>; } & { __: Event<number>; }>; }): void', gave the following error.
+        Type 'Store<\\"a\\" | \\"c\\">' is not assignable to type '(p: number) => \\"a\\" | \\"b\\" | \\"__\\"'.
+          Type 'Store<\\"a\\" | \\"c\\">' provides no match for the signature '(p: number): \\"a\\" | \\"b\\" | \\"__\\"'.
+      Overload 3 of 4, '(config: { source: Unit<number>; match: Unit<\\"a\\" | \\"c\\">; cases: Partial<{ a: Event<number>; c: Event<number>; } & { __: Event<number>; }>; }): void', gave the following error.
+        Type '{ a: Event<number>; b: Event<number>; __: Event<number>; }' is not assignable to type 'Partial<{ a: Event<number>; c: Event<number>; } & { __: Event<number>; }>'.
+          Object literal may only specify known properties, and 'b' does not exist in type 'Partial<{ a: Event<number>; c: Event<number>; } & { __: Event<number>; }>'.
     "
   `)
 })
@@ -134,14 +134,14 @@ test('matcher function case mismatch (should fail)', () => {
   expect(typecheck).toMatchInlineSnapshot(`
     "
     No overload matches this call.
-      Overload 1 of 4, '(config: { source: Unit<number>; match: { [name: string]: Store<boolean> | ((payload: number) => boolean); }; cases: Partial<{ [x: string]: Unit<number>; } & { __: Unit<number>; }>; }): void', gave the following error.
+      Overload 1 of 4, '(config: { source: Unit<number>; match: { [name: string]: Store<boolean> | ((payload: number) => boolean); }; cases: Partial<{ [x: string]: Target; } & { __: Target; }>; }): void', gave the following error.
         Type '(x: number) => \\"a\\" | \\"c\\"' is not assignable to type '{ [name: string]: Store<boolean> | ((payload: number) => boolean); }'.
           Index signature is missing in type '(x: number) => \\"a\\" | \\"c\\"'.
-      Overload 2 of 4, '(config: { source: Unit<number>; cases: Partial<Record<\\"a\\" | \\"__\\" | \\"c\\", Unit<number>>>; match: (x: number) => \\"a\\" | \\"c\\"; }): void', gave the following error.
-        Type '{ a: Event<number>; b: Event<number>; __: Event<number>; }' is not assignable to type 'Partial<Record<\\"a\\" | \\"__\\" | \\"c\\", Unit<number>>>'.
-          Object literal may only specify known properties, and 'b' does not exist in type 'Partial<Record<\\"a\\" | \\"__\\" | \\"c\\", Unit<number>>>'.
-      Overload 3 of 4, '(config: { source: Unit<number>; cases: Partial<Record<string, Unit<number>>>; match: Unit<string | number | symbol>; }): void', gave the following error.
-        Type '(x: number) => \\"a\\" | \\"c\\"' is missing the following properties from type 'Unit<string | number | symbol>': kind, __
+      Overload 2 of 4, '(config: { source: Unit<number>; match: (p: number) => \\"a\\" | \\"c\\"; cases: Partial<{ a: Event<number>; c: Event<number>; } & { __: Event<number>; }>; }): void', gave the following error.
+        Type '{ a: Event<number>; b: Event<number>; __: Event<number>; }' is not assignable to type 'Partial<{ a: Event<number>; c: Event<number>; } & { __: Event<number>; }>'.
+          Object literal may only specify known properties, and 'b' does not exist in type 'Partial<{ a: Event<number>; c: Event<number>; } & { __: Event<number>; }>'.
+      Overload 3 of 4, '(config: { source: Unit<number>; match: Unit<\\"a\\" | \\"b\\" | \\"__\\">; cases: Partial<{ a: Event<number>; b: Event<number>; __: Event<number>; } & { __: Event<number>; }>; }): void', gave the following error.
+        Type '(x: number) => \\"a\\" | \\"c\\"' is missing the following properties from type 'Unit<\\"a\\" | \\"b\\" | \\"__\\">': kind, __
     "
   `)
 })
@@ -162,11 +162,25 @@ test('event with unknown payload in target (should pass)', () => {
 
   expect(typecheck).toMatchInlineSnapshot(`
     "
-    No overload matches this call.
-      Overload 1 of 4, '(config: { source: Unit<string>; match: { [name: string]: Store<boolean> | ((payload: string) => boolean); }; cases: Partial<{ [x: string]: Unit<string>; } & { __: Unit<string>; }>; }): void', gave the following error.
-        Type 'Event<unknown>' is not assignable to type 'Unit<string>'.
-          Types of property '__' are incompatible.
-            Type 'unknown' is not assignable to type 'string'.
+    no errors
+    "
+  `)
+})
+
+test('edge case with target (should pass)', () => {
+  const intervalStore = createStore(Date.now())
+  const filter = createStore(true)
+  const enumType = 3
+  const typeStore = createStore(enumType)
+  const source = guard({source: intervalStore, filter})
+  const caseA = createEvent()
+  const caseB = createEvent()
+
+  split({source, match: typeStore, cases: {[enumType]: caseA, __: caseB}})
+
+  expect(typecheck).toMatchInlineSnapshot(`
+    "
+    no errors
     "
   `)
 })
diff --git a/src/types/__tests__/forest/index.test.ts b/src/types/__tests__/forest/index.test.ts
index a44905da..23e8af82 100644
--- a/src/types/__tests__/forest/index.test.ts
+++ b/src/types/__tests__/forest/index.test.ts
@@ -33,8 +33,8 @@ describe('text', () => {
       "
       No overload matches this call.
         Overload 1 of 2, '(tag: DOMTag, spec: { attr?: PropertyMap | undefined; data?: PropertyMap | undefined; text?: string | number | boolean | Pick<AttributeStore, \\"map\\" | ... 8 more ... | \\"sid\\"> | (string | ... 3 more ... | null)[] | null | undefined; ... 4 more ...; fn?: (() => void) | undefined; }): void', gave the following error.
-          Type 'Store<{ value: string; } | null>' is not assignable to type 'string | number | boolean | Pick<AttributeStore, \\"map\\" | \\"__\\" | \\"kind\\" | \\"getState\\" | \\"subscribe\\" | \\"watch\\" | \\"defaultState\\" | \\"compositeName\\" | \\"shortName\\" | \\"sid\\"> | (string | ... 3 more ... | null)[] | null | undefined'.
-            Type 'Store<{ value: string; } | null>' is not assignable to type 'Pick<AttributeStore, \\"map\\" | \\"__\\" | \\"kind\\" | \\"getState\\" | \\"subscribe\\" | \\"watch\\" | \\"defaultState\\" | \\"compositeName\\" | \\"shortName\\" | \\"sid\\">'.
+          Type 'Store<{ value: string; } | null>' is not assignable to type 'string | number | boolean | Pick<AttributeStore, \\"map\\" | \\"kind\\" | \\"__\\" | \\"getState\\" | \\"subscribe\\" | \\"watch\\" | \\"defaultState\\" | \\"compositeName\\" | \\"shortName\\" | \\"sid\\"> | (string | ... 3 more ... | null)[] | null | undefined'.
+            Type 'Store<{ value: string; } | null>' is not assignable to type 'Pick<AttributeStore, \\"map\\" | \\"kind\\" | \\"__\\" | \\"getState\\" | \\"subscribe\\" | \\"watch\\" | \\"defaultState\\" | \\"compositeName\\" | \\"shortName\\" | \\"sid\\">'.
               Types of property 'map' are incompatible.
                 Type '{ <T>(fn: (state: { value: string; } | null, lastState?: T | undefined) => T): Store<T>; <T>(fn: (state: { value: string; } | null, lastState: T) => T, firstState: T): Store<...>; }' is not assignable to type '{ <T>(fn: (state: DOMProperty, lastState?: T | undefined) => T): Store<T>; <T>(fn: (state: DOMProperty, lastState: T) => T, firstState: T): Store<...>; }'.
                   Types of parameters 'fn' and 'fn' are incompatible.