Skip to content

Commit

Permalink
Merge pull request #248 from bloadvenro/sample-target-forwarding-typings
Browse files Browse the repository at this point in the history
Sample target forwarding typings
(fix #247)
  • Loading branch information
zerobias committed Nov 15, 2019
2 parents 2895ba0 + b5b7933 commit 5b48555
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 20 deletions.
11 changes: 9 additions & 2 deletions packages/effector/index.d.ts
Expand Up @@ -8,6 +8,13 @@
*/
type Tuple<T = unknown> = [T] | T[]

/**
* Non inferential type parameter usage.
*
* @see https://github.com/microsoft/TypeScript/issues/14829#issuecomment-504042546
*/
type NoInfer<T> = [T][T extends any ? 0 : never]

export const version: string

export type kind = 'store' | 'event' | 'effect' | 'domain'
Expand Down Expand Up @@ -452,12 +459,12 @@ export function sample<A, B, C>(
export function sample<A, B, C>(config: {
source: Unit<A>
clock: Unit<B>
fn: (source: A, clock: B) => C
fn: (source: A, clock: B) => NoInfer<C>
target: Unit<C>
greedy?: boolean
}): Unit<C>
export function sample<A>(config: {
source: Unit<A>
source: Unit<NoInfer<A>>
clock: Unit<any>
target: Unit<A>
greedy?: boolean
Expand Down
156 changes: 138 additions & 18 deletions src/types/__tests__/effector/sample.test.js
Expand Up @@ -313,7 +313,6 @@ describe('sample(Store<T>):Store<T>', () => {
--typescript--
Type 'Event<string>' is not assignable to type 'Event<number>'.
--flow--
Cannot assign 'sample(...)' to 'sample_s_edge_incorrect'
const sample_s_edge_incorrect: Event<number> = sample(a, clock)
Expand All @@ -331,25 +330,146 @@ describe('sample(Store<T>):Store<T>', () => {
})
})
test('edge case (should fail)', () => {
const event1 = createEvent()
const event2 = createEvent<{prop: string}>()
describe('`target` forwarding', () => {
it('should pass when a target receives a more strict (or equal) value type from a source', () => {
const source = createStore({a: '', b: ''})
const clock = createEvent()
const target = createEvent<{a: string}>()

sample({source, clock, target})

const store = createStore('value')
expect(typecheck).toMatchInlineSnapshot(`
"
--typescript--
no errors
sample({
source: store,
clock: event1,
fn: () => ({}),
target: event2,
--flow--
no errors
"
`)
})
expect(typecheck).toMatchInlineSnapshot(`
"
--typescript--
no errors

--flow--
no errors
"
`)
it('should pass when a target receives a more strict (or equal) value type from a mapping fn', () => {
const source = createStore(null)
const clock = createEvent()
const fn = () => ({a: '', b: ''})
const target = createEvent<{a: string}>()

sample({source, clock, fn, target})

expect(typecheck).toMatchInlineSnapshot(`
"
--typescript--
no errors
--flow--
no errors
"
`)
})

it('should fail when a target receives a more loose value type from a source', () => {
const source = createStore({a: ''})
const clock = createEvent()
const target = createEvent<{a: string, b: string}>()

sample({source, clock, target})

expect(typecheck).toMatchInlineSnapshot(`
"
--typescript--
No overload matches this call.
The last overload gave the following error.
Type 'Store<{ a: string; }>' is not assignable to type 'Event<unknown> | Effect<unknown, any, any>'.
Type 'Store<{ a: string; }>' is missing the following properties from type 'Event<unknown>': filter, filterMap, prepend, getType
--flow--
Cannot call 'sample' with object literal bound to 'config'
sample({source, clock, target})
^^^^^^^^^^^^^^^^^^^^^^^
property 'b' is missing in object literal [1] but exists in object type [2] in type argument 'T' [3] of property 'target'
const source = createStore({a: ''})
[1] ^^^^^^^
const target = createEvent<{a: string, b: string}>()
[2] ^^^^^^^^^^^^^^^^^^^^^^
export interface Unit<T> extends CovariantUnit<T>, ContravariantUnit<T> {
[3] ^
"
`)
})

it('should fail when a target receives a more loose value type from a mapping fn', () => {
const source = createStore(null)
const clock = createEvent()
const fn = () => ({a: ''})
const target = createEvent<{a: string, b: string}>()

sample({source, clock, fn, target})

expect(typecheck).toMatchInlineSnapshot(`
"
--typescript--
No overload matches this call.
The last overload gave the following error.
Type 'Store<null>' is not assignable to type 'Event<unknown> | Effect<unknown, any, any>'.
Type 'Store<null>' is missing the following properties from type 'Event<unknown>': filter, filterMap, prepend, getType
--flow--
Cannot call 'sample' with object literal bound to 'config'
sample({source, clock, fn, target})
^^^^^^^^^^^^^^^^^^^^^^^^^^^
property 'b' is missing in object literal [1] but exists in object type [2] in type argument 'T' [3] of property 'target'
const fn = () => ({a: ''})
[1] ^^^^^^^
const target = createEvent<{a: string, b: string}>()
[2] ^^^^^^^^^^^^^^^^^^^^^^
export interface Unit<T> extends CovariantUnit<T>, ContravariantUnit<T> {
[3] ^
"
`)
})

it('should fail when a target receives a more loose value type from a source (edge case for {} type)', () => {
const source = createStore({})
const clock = createEvent()
const target = createEvent<{a: string, b: string}>()

sample({source, clock, target})

expect(typecheck).toMatchInlineSnapshot(`
"
--typescript--
No overload matches this call.
The last overload gave the following error.
Type 'Store<{}>' is not assignable to type 'Event<unknown> | Effect<unknown, any, any>'.
Type 'Store<{}>' is missing the following properties from type 'Event<unknown>': filter, filterMap, prepend, getType
--flow--
no errors
"
`)
})

it('should fail when a target receives a more loose value type from a mapping fn (edge case for {} type)', () => {
const source = createStore(null)
const clock = createEvent()
const fn = () => ({})
const target = createEvent<{a: string, b: string}>()

sample({source, clock, fn, target})

expect(typecheck).toMatchInlineSnapshot(`
"
--typescript--
No overload matches this call.
The last overload gave the following error.
Type 'Store<null>' is not assignable to type 'Event<unknown> | Effect<unknown, any, any>'.
Type 'Store<null>' is not assignable to type 'Event<unknown>'.
--flow--
no errors
"
`)
})
})

1 comment on commit 5b48555

@vercel
Copy link

@vercel vercel bot commented on 5b48555 Nov 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.