Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable the programmatic generation of overloads like feature in types. #23669

Closed
sledorze opened this issue Apr 24, 2018 · 10 comments
Closed

Enable the programmatic generation of overloads like feature in types. #23669

sledorze opened this issue Apr 24, 2018 · 10 comments
Labels
Duplicate An existing issue was already created

Comments

@sledorze
Copy link

sledorze commented Apr 24, 2018

I've not found anything related:
Search Terms:
overloads, programmatic

The context that explain the need to help understand the suggestion:

I'm using the io-ts (https://github.com/gcanti/io-ts) library which enables the creation of encoders/decoders by combining simpler ones.

This library can be extended by creating new types of codecs.
From a codec representation, I want to derive several generations programmatically (jsonSchema, random generators, etc..).
So I'm creating a conversion from a selected union of all base standard io-ts codecs and provides the end user of the library with a function to defines the remaining one it needs to handle for a particular codec it uses (for instance he may use a specific codec for jsJoda date in its User codec to represent its birthDate).
He may want to generate random data from that Codec but only providing the definition of it's jsJoda codec.

So the use case is a library that needs to expose a function to handles cases based on a union of types (say A | B) to represent the non standard types (codecs in the example) and requires to return specific values based on those types ( Result<A> | Result<B> ) but depending on the actual input values, like so:
(x: A) => Result<A> and (x: B) => Result<B>
and NOT like so:
(x: B) => Result<A> or (x: A) => Result<B>.

As of today, there's no way (known to me) to derive a type ((x: A) => Result<A>) & ((x: B) => Result<B>) from A | B and,
given that signature ((x: A) => Result<A>) & ((x: B) => Result<B>), to implement it.

However; the abstraction seems to exist in classes via Overloads.

Related code:

interface Result<T> {
  res: T
}

class A {
  type: 'a' = 'a'
}
class B {
  type : 'b' = 'b'
}
type All = A | B

type Expected = ((x: A) => Result<A>) & ((x: B) => Result<B>)

const foo: Expected = (x: All) => { // Type '(x: All) => Result<A> | Result<B>' is not assignable to type 'Expected'
  if (x.type === 'a') {
    return 1 as any as Result<A>
  } else {
    return 1 as any as Result<B>
  }
}

// I need foo to unify with `((x: A) => Result<A>) & ((x: B) => Result<B>)` based on its control flow and not only `(x: All) => Result<A> | Result<B>`

// note about types correctly dispatching the result type based on the input type (like with overloads)
const f: Expected = 1 as any
f(1 as any as A) // Result<A> (ok) (and shows ‘overload info)
f(1 as any as B) // Result<B> (ok) (and shows overload info)

The suggestion is then to support that needs by providing both a way to encode overloads programatically (from types and not on classes) and their implementation (dispatch)

@SimonMeskens
Copy link

SimonMeskens commented Apr 25, 2018

I'm not sure we need this, you could just use this definition of Expected and it works:

type Expected = <T extends All>(x: T) => 
    T extends A ? Result<A> : 
    T extends B ? Result<B> : 
    any;

@SimonMeskens
Copy link

Actually, I think I get what you mean, it's not possible to assign to such a type either. The problem is not creating a type that maps different types to results, the problem is assigning to it.

I'll have a look if the language is currently capable of that.

@sledorze
Copy link
Author

@SimonMeskens indeed, there is two issues.

You seem to consider that passing from
A | B
to
T extends A ? Result<A> : T extends B ? Result<B> : any;
may not be an issue; do you have an implementation example to share?

@SimonMeskens
Copy link

Not from any cursory testing no. It seems we can neither assign to the intersection or the conditional, unless there's a way I'm not seeing.

@SimonMeskens
Copy link

There's a third option btw:

interface Expected  {
    (x: A): Result<A>
    (x: B): Result<B>
}

We can't assign to this one either.

@sledorze
Copy link
Author

That's a bunch of interesting use cases to crack!

@mhegazy
Copy link
Contributor

mhegazy commented Jul 18, 2018

I think the type should be defined as:

type Expected = <T extends A | B>(x: T) => T extends A ? Result<A> : Result<B>;

The problem is today there is no way to implement this function without casts. we have been using
#23132 to track that.

@mhegazy mhegazy added the Duplicate An existing issue was already created label Jul 18, 2018
@sledorze
Copy link
Author

@mhegazy well, its not exactly a Duplicate.
I be correct, I would say that one potential solution to this issue has problems which are tracked by #23132 but I guess there's no label for that.

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@sledorze
Copy link
Author

Provided its not a duplicate of the other issue.
There's some over Automation swallowing a real non addressed issue here...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants