Skip to content

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

Closed
@sledorze

Description

@sledorze

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)

Activity

SimonMeskens

SimonMeskens commented on Apr 25, 2018

@SimonMeskens

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

SimonMeskens commented on Apr 25, 2018

@SimonMeskens

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

sledorze commented on Apr 25, 2018

@sledorze
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

SimonMeskens commented on Apr 25, 2018

@SimonMeskens

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

SimonMeskens commented on Apr 25, 2018

@SimonMeskens

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

sledorze commented on Apr 25, 2018

@sledorze
Author

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

mhegazy

mhegazy commented on Jul 18, 2018

@mhegazy
Contributor

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.

sledorze

sledorze commented on Jul 19, 2018

@sledorze
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

typescript-bot commented on Jul 30, 2018

@typescript-bot
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

sledorze commented on Jul 30, 2018

@sledorze
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

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @sledorze@SimonMeskens@mhegazy@typescript-bot

        Issue actions

          Enable the programmatic generation of overloads like feature in types. · Issue #23669 · microsoft/TypeScript