fp-ts icon indicating copy to clipboard operation
fp-ts copied to clipboard

Ensuring that bind and bindW pass the correct params through rather t…

Open feydan opened this issue 4 years ago • 2 comments

…han get rewritten by the function passed in

Fixes https://github.com/gcanti/fp-ts/issues/1583

The following code improperly raises a type error:

  const func1 = (i: {arg1: string}) => TE.right('result1')
  const func2 = (i: {arg2: string, result1: string}) => TE.right('result2')

  pipe(
    TE.right({arg1: 'arg1', arg2: 'arg2'}),
    TE.bindW('result1', func1),
    TE.bindW('result2', func2),
  )

This is because this line improperly rewrites the parameter list that gets passed into the next function in the pipe TE.bindW('result1', func1),

This MR changes the passed in function to have its own generic that extends the param list. This allows the params to flow through as expected.

edit: formatting

feydan avatar Sep 15 '21 18:09 feydan

Unfortunately, this seems to cause another issue:

// proper param passthrough
    const c = (p: { a: number }) => _.right<string, number>(p.a)
    const d = (p: { b: string }) => _.right<string, string>(p.b)
    U.deepStrictEqual(
      await pipe(
        _.right<string, number>(1),
        _.bindTo('a'),
        _.bind('b', () => _.right('b')),
        _.bind('c', c),
        _.bind('d', d),
        _.bind('e', _.fromIOK(i => () => 'io')) // Type 'A2' is not assignable to type 'A2'. Two different types with this name exist, but they are unrelated.
      )(),
      E.right({ a: 1, b: 'b', c: 1, d: 'b', e: 'io' })
    )

Looking into alternatives.

feydan avatar Sep 15 '21 18:09 feydan

Unfortunately, this seems to cause another issue:

// proper param passthrough
    const c = (p: { a: number }) => _.right<string, number>(p.a)
    const d = (p: { b: string }) => _.right<string, string>(p.b)
    U.deepStrictEqual(
      await pipe(
        _.right<string, number>(1),
        _.bindTo('a'),
        _.bind('b', () => _.right('b')),
        _.bind('c', c),
        _.bind('d', d),
        _.bind('e', _.fromIOK(i => () => 'io')) // Type 'A2' is not assignable to type 'A2'. Two different types with this name exist, but they are unrelated.
      )(),
      E.right({ a: 1, b: 'b', c: 1, d: 'b', e: 'io' })
    )

Looking into alternatives.

I think I found a solution -- the change is committed.

feydan avatar Sep 15 '21 18:09 feydan

npm run fix-prettier should fix the CI failure

gcanti avatar Sep 05 '22 05:09 gcanti

Thank you @feydan

gcanti avatar Sep 06 '22 16:09 gcanti

I'm trying out 2.13.0-rc.4, and this change seems to cause a type of failure in an existing (working) project. I'm seeing if I can create a reproducible failure/fix.

thewilkybarkid avatar Sep 20 '22 09:09 thewilkybarkid

So the failure is related to inference and ts-pattern in https://github.com/PREreview/prereview.org/blob/b9f3de1477e2904fcbeee2ed70cc7e1aa7a24a6e/src/infrastructure.ts#L145-L153

Seems like the union type causes the exhaustiveness check to fail.

I can extract a typed function which gets around the issue, but this wasn't possible before this change. 😃

thewilkybarkid avatar Sep 20 '22 09:09 thewilkybarkid

Reproduction with ts-pattern

I'll open a ts-pattern issue due to the problem there with generics (edit: https://github.com/gvergnaud/ts-pattern/issues/111).

thewilkybarkid avatar Sep 20 '22 09:09 thewilkybarkid

Thank you @thewilkybarkid, I'll revert this change as is causing a regression (might be rescheduled for 2.14)

gcanti avatar Sep 20 '22 10:09 gcanti