Giter VIP home page Giter VIP logo

Comments (13)

Avaq avatar Avaq commented on June 3, 2024 2

Following some links, I found this comment:

Overloads, whenever possible, should always have a final overload that covers all of the cases in a more general way
-- microsoft/TypeScript#40413 (comment)

This makes it sound like perhaps the problematic overload can be rephrased for TypeScript to "fall back" to the "map on Future" case when it can't resolve the overload. I will investigate this option.

from fluture.

tjjfvi avatar tjjfvi commented on June 3, 2024 2

it brought this repo to mind as it's the HKT implementation that has made the most sense to me to date, but I'm not convinced it's any simpler than his solution. I learned a ton today! Many thanks to you both ๐Ÿ™

That traverses down the type and replaces _<0>, _<1>, etc., which thus doesn't support conditional types, which is normally half of my use case ๐Ÿ˜„ . Creating the HKTs with it is a bit simpler, however, so if you're just using HKTs for a Functor-esque purpose like this, it's probably better.

from fluture.

EricCrosson avatar EricCrosson commented on June 3, 2024

I should note that chain can infer types just fine (i.e. same behavior as fluture 11.x), so this is specific to map

from fluture.

Avaq avatar Avaq commented on June 3, 2024

Hi @EricCrosson. Thanks for the report. I think it's because the second argument to map is overloaded with support for the ConcurrentFuture type besides the Future type:

Fluture/index.d.ts

Lines 138 to 143 in 2f12660

export function map<RA, RB>(mapper: (value: RA) => RB): <T extends FutureInstance<any, RA> | ConcurrentFutureInstance<any, RA>>(source: T) =>
T extends FutureInstance<infer L, RA> ?
FutureInstance<L, RB> :
T extends ConcurrentFutureInstance<infer L, RA> ?
ConcurrentFutureInstance<L, RB> :
never;

TypeScript cannot infer types from overloaded functions (microsoft/TypeScript#32418 (comment)).


In Fluture v11, this overload was incorrectly specified at the first function argument:

Fluture/index.d.ts

Lines 271 to 277 in 00959c7

/** Map over the resolution value of the given Future. See https://github.com/fluture-js/Fluture#map */
export function map<L, RA, RB>(mapper: (value: RA) => RB, source: FutureInstance<L, RA>): FutureInstance<L, RB>
export function map<L, RA, RB>(mapper: (value: RA) => RB): (source: FutureInstance<L, RA>) => FutureInstance<L, RB>
/** Map over the resolution value of the given ConcurrentFuture. See https://github.com/fluture-js/Fluture#map */
export function map<L, RA, RB>(mapper: (value: RA) => RB, source: ConcurrentFutureInstance<L, RA>): ConcurrentFutureInstance<L, RB>
export function map<L, RA, RB>(mapper: (value: RA) => RB): (source: ConcurrentFutureInstance<L, RA>) => ConcurrentFutureInstance<L, RB>

This means that TypeScript always resolves to the first overload that matches the input function (as opposed to the type of Functor), which is the version of map used on Future (see #400). So in v11, it worked for Future instances, but not for ConcurrentFuture instances. This was fixed over several iterations: first #401 and then #403.


I believe this is a case where fixing one issue introduces the other, and vice-versa. I've also had trouble with TypeScript's inference from overloaded functions when I was trying to do #438, leading me to have abandoned it for now. I would love for this problem to be solved somehow, but no luck so far. We can leave this issue open for visibility.

from fluture.

Avaq avatar Avaq commented on June 3, 2024

Oh, and the reason my preference is to leave it at the current solution, and not go back to the v11 way (essentially dropping support for map on ConcurrentFuture), is because the problem caused by the current approach is easier to solve in userland, via a type annotation. In other words, it seems like the lesser of two evils.

from fluture.

Avaq avatar Avaq commented on June 3, 2024

@EricCrosson As a work-around, you could create a Future-specialized map function, eg:

import * as F from 'fluture'

export function map<RA, RB>(mapper: (value: RA) => RB):
  <L>(source: F.FutureInstance<L, RA>) => F.FutureInstance<L, RB> {
  return F.map (mapper)
}

///////////////////////////////////////////////

F.resolve(5)
    .pipe(map(value => value.toString()))

from fluture.

EricCrosson avatar EricCrosson commented on June 3, 2024

@Avaq, thank you for the quick response and suggested workaround!

I appreciate the historical context you have provided. There's a lot to read and think about, so I may take some time to digest all of this.

from fluture.

EricCrosson avatar EricCrosson commented on June 3, 2024

Another option I have been thinking about is to create more separation between the Future and ConcurrentFuture types, so that both can support their entire feature-set "out of the box", but I like the sound of the final overload much more

from fluture.

Avaq avatar Avaq commented on June 3, 2024

@EricCrosson I've started working on this, although have been unsuccessful in finding a solution. See #457.

from fluture.

Avaq avatar Avaq commented on June 3, 2024

I also asked for help with this issue on TypeScript's Discord: https://discord.com/channels/508357248330760243/740274647899308052/796759112607203399

from fluture.

EricCrosson avatar EricCrosson commented on June 3, 2024

Awesome, I didn't know there was a TypeScript discord! I'll check out your post there and the PR to see if I can help

from fluture.

Avaq avatar Avaq commented on June 3, 2024

Someone on the Discord channel found a solution. I committed it to #457. Perhaps you could install npm i fluture-js/fluture#avaq/map-ts and test if this has solved your issue? Note that this may not work with ts-node due to its reliance on CJS, but you can test with tsc.

from fluture.

EricCrosson avatar EricCrosson commented on June 3, 2024

Sure! I'm reading through the discord conversation now -- coolest back-and-forth I've seen in a while ๐Ÿ˜Ž

Where @tjjfvi mentioned

I've never fully grokked the other [HKT] encodings I've seen

it brought this repo to mind as it's the HKT implementation that has made the most sense to me to date, but I'm not convinced it's any simpler than his solution. I learned a ton today! Many thanks to you both ๐Ÿ™

Testing fluture-js/fluture#avaq/map-ts locally

Yes sir! The example in my initial post compiles without a hitch, and my editor correctly infers that value is of type number. This ticket can be closed. Dynamite! ๐Ÿงจ

Consider me officially excited to upgrade my projects from fluture 11 to fluture ๐Ÿš€

from fluture.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.