Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I express this in Typescript?

Let's say I have an interface A:

interface A {
  foo: number
  bar: string
}

And I have a generic type Option:

type Option<T> = {
  map: () => T
}

Then I create a new interface B from A and Option:

interface B {
  foo: Option<number>
  bar: Option<string>
}

How can I make this operation more general? Ie. The API I want is:

type B = Lift<A>

Where Lift automatically maps each member of A to an Option. Note that A can have any number of members, of any type.

How can I implement Lift? If this is not possible in TypeScript, does anyone have a Scala/Haskell solution?

like image 880
bcherny Avatar asked Apr 27 '16 20:04

bcherny


Video Answer


1 Answers

You are looking for higher-kinded types. Here it is in Scala:

trait FooBar[M[_]] {
  val foo: M[Integer]
  val bar: M[String]
}

type Identity[X] = X
type A = FooBar[Identity]
type B = FooBar[Option]

You can use any second-order types e.g.:

type C = FooBar[List]

But these will not compile:

// type S = FooBar[String] ---> String is a first-order type
// type M = FooBar[Map]    ---> Map[K, V] is a third-order type

Unfortunately, this has not yet made it into TypeScript but there is an open issue for it: https://github.com/Microsoft/TypeScript/issues/1213

like image 89
pathikrit Avatar answered Sep 22 '22 14:09

pathikrit