flow icon indicating copy to clipboard operation
flow copied to clipboard

Fix Function.prototype.apply.bind

Open goodmind opened this issue 6 years ago • 14 comments

Fixes #5681

const fn = (a: number) => {}
export const fnApply = fn.apply.bind(fn) // no error

Also adds argument to Function$Prototype$Apply

declare var fnApply: Function$Prototype$Apply<typeof fn>

goodmind avatar Jul 02 '19 18:07 goodmind

A silly question: What significance does binding the apply function itself have? Can you share an example where the observable effect of checking is different?

If it is significant, I think the solution of adding a this type to the internal representation of ApplyT is reasonable. However, I don't think we should add a type parameter to the annotation syntax, or at least not until the overall this-type story is sorted.

samwgoldman avatar Jul 09 '19 17:07 samwgoldman

@samwgoldman it would be possible to apply $Compose or other custom functions on type-level

goodmind avatar Jul 09 '19 17:07 goodmind

Can you please share an example? :)

samwgoldman avatar Jul 09 '19 17:07 samwgoldman

function spread(fn) {
  return Function.apply.bind( fn, null );
}

spread(fn)([1, 2, 3]) // fn(1, 2, 3)

mroch avatar Jul 09 '19 17:07 mroch

https://github.com/lttb/flown/blob/master/src/Reduce/index.js

type Apply<Fn, Args> = $Call<Function$Prototype$Apply<Fn>, null, Args>
// basically $Call with tuple

declare function reduce<Fn, A, T>(Fn, A, T): $Call<
  Apply<
    $ComposeReverse,
    $TupleMap<T, Fn>,
  >
, A>

export type _Reduce = typeof reduce

export type Reduce<Fn, A, T> = $Call<_Reduce, Fn, A, T>

goodmind avatar Jul 09 '19 17:07 goodmind

type MergeAll<T> = Reduce<<X, V>(V) => X => { ...$Exact<X>, ...$Exact<V> }, {}, T>

declare function mergeAll<A>(A): MergeAll<A>

const x = mergeAll([{ a: 1 }, { b: 1 }, { c: 1 }, { a: 2 }])

;(x: { a: 2, b: 1, c: 1 })

/**
 * $ExpectError
 *
 * the type of 'c' is incompatible with number
 */
;(x: { a: 2, b: 1, c: '1' })

goodmind avatar Jul 09 '19 18:07 goodmind

@goodmind I don't see how these examples are related to the linked issue, or Function.prototype.apply/bind. I would much prefer to focus on the problem at hand, since there's enough work involved in supporting the use case from Marshall's example.

  1. I still don't think we should add a type argument to Function$Prototype$Apply. Even if it makes some things expressible, it's putting the cart before the horse.
  2. Per Marshall's example, adding the this type to the internal FunApplyT repr isn't enough, we also need to add the partial argument list.
  3. The implementation here does not look correct (will comment inline) so some tests are definitely needed.

samwgoldman avatar Jul 09 '19 18:07 samwgoldman

@samwgoldman now it should work, I didn't expose partial apply to arguments itself, only to use_t

goodmind avatar Jul 09 '19 20:07 goodmind

@samwgoldman how it would work then for this case

type Apply<Fn, Args> = $Call<Function$Prototype$Apply<Fn>, null, Args>

goodmind avatar Jul 09 '19 20:07 goodmind

We don't need it to fix #5681. If you want to support another case, I think that you should write up a more thorough proposal. For example, why should we support that?

samwgoldman avatar Jul 09 '19 20:07 samwgoldman

@samwgoldman maybe I can remove argument if you don't want it and decide later how to make my case work? (or write proposal)

goodmind avatar Jul 09 '19 20:07 goodmind

Yeah. I would want to have a full understanding of your use case before adding something. It's possible that another solution would be better. I'm not opposed to adding something later, but we need to follow a process to make sure that we're adding the right things for the right reasons.

samwgoldman avatar Jul 09 '19 20:07 samwgoldman

@samwgoldman removed it

goodmind avatar Jul 09 '19 21:07 goodmind

Probably related issue, methods doesn't have function prototype https://flow.org/try/#0MYGwhgzhAECC0G8BQ1oQC5nQS2NAZgBRgBc0AdgK4C2ARgKYBOAlIitAL5JdKwB0+PmAAOwkAE9CVECAA00ANoByJQF1mQA

goodmind avatar Jul 09 '19 21:07 goodmind