Repository: TypeScript
Issue: Generic values
Labels: Suggestion,Awaiting More Feedback

TypeScript supports generic type/interface/class declarations. These features serve as an analog of "type constructors" in other type systems: they allow us to declare a type that is parameterized over some number of type arguments.

TypeScript also supports generic functions. These serve as limited form of parametric polymorphism: they allow us to declare types whose *inhabitants* are parametrized over some number of type arguments. Unlike in certain other type systems however, these types can only be function types.

So for example while we can declare:

```ts
type Id = <T>(x : T) => T

const test : Id = x => x
```

we cannot declare (for whatever reason):

```ts
type TwoIds = <T> { id1: (x: T) => T, id2: (x: T) => T }

const test : TwoIds = { id1: x => x, id2: x => x }
```

One result of this limitation is that the type constructor and polymorphism features interact poorly in TypeScript. The problem applies even to function types: if we abstract a sophisticated function type into a type constructor, we can no longer universally quantify away its type parameters to get a generic function type. This is illustrated below:

```ts
// This works
type Id = <T>(x : T) => T

// This should also work
type IdT<T> = (x: T) => T
type Id = <T> IdT<T> // but is impossible to express
```

Another problem is that it is often useful to quantify over types other than bare functions, and TypeScript prohibits this. As an example, this prevents us from modeling polymorphic lenses:

```ts
type Lens<T, U> = {
    get(obj: T): U
    set(val: U, obj: T): T
}

// no way to express the following type signature
const firstItemInArrayLens: <A> Lens<A[], A> = {
    get: arr => arr[0],
    set: (val, arr) => [val, ...arr.slice(1)]
}

firstItemInArrayLens.get([10])      // Should be number
firstItemInArrayLens.get(["Hello"]) // Should be string
```

In this case, a workaround is to break down the type into functions and move all the polymorphic quantification there, since functions are the only values that are allowed to be polymorphic in TypeScript:

```ts
type ArrayIndexLens = {
    get<A>(obj: A[]): A
    set<A>(val: A, obj: A[]): A[]
}

const firstItemInArrayLens: ArrayIndexLens = { ... }
```

By contrast, in Haskell you'd simply declare an inhabitant of a polymorphic type: `firstItemInArrayLens :: forall a. Lens [a] a`, similarly to the pseudocode declaration `const firstItemInArrayLens: <A> Lens<A[], A>`:

```hs
{-# LANGUAGE ExplicitForAll #-}

data Lens s a = Lens { get :: s -> a, set :: a -> s -> s }

firstItemInArrayLens :: forall a. Lens [a] a
firstItemInArrayLens = Lens { get = _, set = _ }
```

In some sense TypeScript has even less of a problem doing this than Haskell, because Haskell has concerns like runtime specialization; it must turn every polymorphic expression into an actual function which receives type arguments.

TypeScript just needs to worry about assignability; at runtime everything is duck typed and "polymorphic" anyway. A more polymorphic term (or a term for which a sufficiently polymorphic type can be inferred) can be assigned to a reference of a less polymorphic type. 

Today, a value of type `<A> (x: A) => A` is assignable where a `(x: number) => number` is expected, and in turn the expression `x => x` is assignable where a `<A> (x: A) => A` is expected. Why not generalize this so an `<A> Foo<A>` is assignable wherever a `Foo<string>` is expected, and it is possible to write: `const anythingFooer: <A> Foo<A> = { /* implement Foo polymorphically */ }`?