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

Preserve pass-through parameter type in generic function return type #31529

Open
5 tasks done
jelbourn opened this issue May 22, 2019 · 2 comments
Open
5 tasks done

Preserve pass-through parameter type in generic function return type #31529

jelbourn opened this issue May 22, 2019 · 2 comments
Labels
Needs More Info The issue still hasn't been fully clarified

Comments

@jelbourn
Copy link

Search Terms

generic, propagate, multiple, preserve, argument, parameter, pass-through

Suggestion

When a generic function expresses its return type in terms of an argument constraint, the originally given argument type should be preserved/passed-through when the function is called.

Example

interface HasId {
  id: string;
}

interface SpecialArray<D> {
  getSpecialItem(): D;
}

function go<T extends Array<D>, D>(x: T): SpecialArray<D> {
  return x as any;
}

const v: Array<HasId> = [{id: 'one'}];

// We expect a return type of `SpecialArray<HasId>` but instead we
// get `SpecialArray<{}>`.
const w = go(v);

(playground)

Use Cases

My primary use-case for this has been compositional mixins. I want to be able to take some class with a type like HasItems<SomeItem> and augment it with a mixin to add a behavior HasActiveItem<D>, where the mixin has recognizes the SomeItem passed in and propagates it through to satisfy subsequent mixin calls.

This can be done today by omitting one of the generics from the function signature and duplicating those bits of typing in both the parameters and the return type; the remaining generic only captures the "Item" part of the signature.

Checklist

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.
@dragomirtitian
Copy link
Contributor

dragomirtitian commented May 22, 2019

Typescript will not infer type parameters if they are not used in the parameters of the function. Other type parameters are not (as far as I know) an inference site for type parameters.

There are several ways of getting the code above to work. You could just use D and remove T:

interface HasId {
  id: string;
}

interface SpecialArray<D> {
  getSpecialItem(): D;
}

function go<D>(x: D[]): SpecialArray<D> {
  return x as any;
}

const v: Array<HasId> = [{id: 'one'}];

const w = go(v); //SpecialArray<HasId>

Or use T and use a conditional type to extract the item type:

function go<T extends any[]>(x: T): SpecialArray<T extends Array<infer D> ? D : never> {
  return x as any;
}

const v: Array<HasId> = [{id: 'one'}];

const w = go(v); //SpecialArray<HasId>

While it would be nice if your code would work as is, since there are already ways to achieve the same thing I'm not sure the extra complexity to infer one type parameter from the other is justified.

@RyanCavanaugh RyanCavanaugh added the Needs More Info The issue still hasn't been fully clarified label Jun 13, 2019
@RyanCavanaugh
Copy link
Member

@dragomirtitian 's analysis is correct.

Without use cases that require new functionality, there's not really a suggestion here. Generic functions are already inferred in many places where appropriate, but the function described in OP doesn't need that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs More Info The issue still hasn't been fully clarified
Projects
None yet
Development

No branches or pull requests

3 participants