jonschlinkert / kind-of

Get the native JavaScript type of a value, fast. Used by superstruct, micromatch and many others!
https://github.com/jonschlnkert
MIT License
351 stars 40 forks source link

Async function support? #22

Open johnrees opened 6 years ago

johnrees commented 6 years ago

Are there plans to identify async functions?

I've been doing checks with example below but I am sure that it'll be a very fragile approach.

const fn = async function() {};
kindOf(fn); // function
fn[Symbol.toStringTag] === 'AsyncFunction'; // true
jonschlinkert commented 6 years ago

I'm not sure how I feel about this. It's easy to add, and I think it's an interesting idea, but how often will users want to know if the function is async versus just a function?

If we did add support for this, I think it would need to be optional, or another method.

johnrees commented 6 years ago

Sure, no worries @jonschlinkert, I'll leave it up to you.

I can't speak for others but I've run into that situation a few times recently whilst working with observables and partially applied functions. It was helpful to know if I'd definitely be receiving a Promise.

tunnckoCore commented 6 years ago

Ha. Coming here obviously for second time, haha.

I'm for adding that too. Probably behind option - kindOf(val, {foo:true}).

Yea, such cases are some rare cases and adding option for this may sounds ugly but..

jonschlinkert commented 6 years ago

I agree, I've been thinking about this more and it makes sense to expose something for this. I'll try to brew something up.

mindplay-dk commented 2 years ago

This feature is a breaking change, as previously covered in this rejected PR.

If some client uses a check like kindOf(val) === "function", this change would break that.

The other issue is, as OP pointed out, this is in fact fragile - because this works:

(async function () {})[Symbol.toStringTag] === 'AsyncFunction' // => true

But this does not:

(function () { return Promise.resolve() })[Symbol.toStringTag] === 'AsyncFunction' // => false

In practical terms, if this was implemented, transpilers such as Babel would break your code when it converts an async function to a plain function.

In Javascript terms, there is really no distinction in terms of types - the presence of Symbol.toStringTag reveals an implementation detail, not something related to the type per se, as you can see here:

typeof (async function () {}) // => 'function'

(async function () {}) instanceof Function // => true

The type of an async function is still Function - whether you happen to write an asynchronous function using the async keyword or returning a Promise is an implementation detail, and it should be thought of as syntactic sugar. (even if that's not how it's implemented by the engine.)

One should expect to be able to refactor freely between async and returning a Promise - so this change would break normal developer expectations about Javascript functions.

If there is a case where you needed to know the return-type of a function, the only reliable approach is to call the function first, and then check if the type of the returned value is Promise.

I don't think this feature belongs in a type-checking library - it already provides the ability to check the returned value from a function (to see if it's a Promise) so this feature isn't really about type-checking.

I would vote to close this issue.