ericelliott/rtype

Should we have this?

Closed this issue · 19 comments

Cool. Looking over a few of their examples, they make a good case (.bind(), .apply() w/mixins). I'm open to it.

Want to write up a few example use cases?

It's not a rhetorical question. This one is out of my league.
I suppose it's missing, that's it.

Yes, we should. this is like regular parameters an argument that is passed to a function call. We should be able to type it.

Things that should be considered:

Ps: I just quickly scaned the TypeScript discussion yet.

@maiermic In most cases, this should not be typed by the function using this, but instead, define some typed subset of this. Because this is determined by the call-site usage, it's impossible for the user of this to accurately determine its full exact shape.

it's impossible for the user of this to accurately determine its full exact shape.

@ericelliott Who is the user of this? The author of the function?

What he's saying is that, unless you have a way to declare the executing context, this can be (re-)set to anything. So using this would require to have its pendant: the context himself declared in the documentation and tightly coupled somehow to the function signature.

That's why it's only useful—without any prior context setting—when the function doesn't expect something in particular.

In a lot of languages this is considered redundant.

I am closing this for now and moving it to the backlog: it's not essential for the MVP.

@amcdnl

In a lot of languages this is considered redundant.

Any example of a language with type annotations where this is not bound to the method? In statically typed languages like Java and C# this is of the enclosing class or interface type.

In light of #120 and the discussion that ensued on #110, I am reopening this.

I am gonna re-introduce the problem at hand for the ones dropping by.

The main use case that we need to cover is—as explained by @ericelliott before—being able to restrict the type of "the call-site".

Now here's my take on this (pun intended), I think it would make sense to place it just before the function signature. e.g. <here> signatureName(paramName: Type) => ReturnType

If we really want to make it obvious we could reuse something recognizable by any JS dev:

// assumes Example has been defined

// either
Example.signatureName(paramName: Type) => ReturnType
// or
Example[signatureName(paramName: Type) => ReturnType]

I don't particularly support this proposal. The priority for me is the position/order.
Which means that the introduction of a new operator would do just as well:

Example :: signatureName(paramName: Type) => ReturnType

The :: syntax seems promising for this, mirroring the ECMAScript This-Binding Syntax proposal:

// Iterable::first() => a

const first = function () {
  const [a] = this;
  return a;
};

first.call([1,2,3]); // 1

I forgot about that proposal but now that you remind me I did participate in tc39/proposal-bind-operator#24

I like your example, it's simple and it's reusing a reserved type that has already been defined, much clearer than mine.

The problem will be the error case. The way it will be handled is tool-dependent hence off-topic in the rtype specification.

@ericelliott

  1. Which syntax(es) should be supported?
// A
Iterable::first() => a

// B
::Iterable.first() => a

I am leaning toward A. Both is also a valid option.

  1. Are spaces allowed around ::?

If so, shouldn't it be recommended?

I think you're misunderstanding the second syntax. In the TC39 proposal, the ::map() syntax means that the return value from the previous expression will be bound to this inside map().

I'm not sure how we'd use that in Rtype.

obj::func(val)
// is equivalent to:
func.call(obj, val)

::obj.func(val)
// is equivalent to:
func.call(obj, val)

Are you telling me that https://babeljs.io/docs/plugins/transform-function-bind/#detail is erroneous?

OK, but not sure how that makes sense.

::obj.func(val)
// is equivalent to:
func.call(obj, val)
// is equivalent to:
obj.func(val)

You were right it was a typo:

::obj.func(val)
// is equivalent to:
obj.func.call(obj, val)