2016-04-27 8 views
15

Lassen Sie uns sagen, dass ich eine Schnittstelle A haben:Wie kann ich das in Typoskript ausdrücken?

interface A { 
    foo: number 
    bar: string 
} 

Und ich habe einen generischen Typ Option:

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

Dann erstelle ich eine neue Schnittstelle B von A und Option:

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

Wie kann ich diese Operation allgemeiner machen? Ie. Die API ich will, ist:

type B = Lift<A> 

Wo Lift Karten automatisch jedes Mitglied A zu einem Option. Beachten Sie, dass A beliebig viele Mitglieder haben kann.

Wie kann ich Lift implementieren? Wenn dies in TypeScript nicht möglich ist, hat jemand eine Scala/Haskell-Lösung?

Antwort

2

Gute Nachrichten: Mit TypeScrip 2.1.0 t, dies ist nun möglich, über Mapped Types:

type Option<T> = { map() => T }; 
type OptionsHash<T> = { [K in keyof T]: Option<T[K]> }; 
function optionsFor<T>(structure: T): OptionsHash<T> { ... }; 

let input = { foo: 5, bar: 'X' }; 
let output = optionsFor(input); 
// output is now typed as { foo: { map:() => number }, bar: { map:() => string } } 

Das Gegenteil ist auch möglich:

function retreiveOptions<T>(hash: OptionsHash<T>): T { ... }; 

let optionsHash = { 
    foo: { map() { return 5; } }, 
    bar: { map() { return 'x'; } } 
}; 
let optionsObject = retreiveOptions(optionsHash); 
// optionsObject is now typed as { foo: number, bar: string } 
+1

Mapped Typen sind super cool - danke für die Antwort. – bcherny

4

Ich habe mich eine Weile nicht mit TypeScript beschäftigt (ich denke, es war in der Version 1.0), also kann ich nicht wirklich sagen, ob es jetzt da ist.

Was Sie wollen, erfordert ein Typ-System-Feature namens höher geknotete Typen; es erlaubt, Typen zu konstruieren, indem man sie als Argumente an Typkonstruktoren übergibt, ähnlich wie bei der Funktion application, die auf die Typ-Ebene gehoben wird.

Sie müssen die Definition von A anpassen, damit dies funktioniert. Hier ist, wie würde ich erreichen, was Sie in Haskell wollen:

-- First, I need a more general definition for A 
data GeneralizedA f = A { foo :: f Int, bar :: f String } 

-- So that I can re-encode the original A like this : 
type A = GeneralizedA Identity 

-- Guessing what the Option type would be since 
-- Haskell's type system is more precise here : 
data Option a = Option { optionMap :: IO a } 

-- And here's the result : 
type B = GeneralizedA Option 
9

Sie suchen higher-kinded types suchen. Hier ist es 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] 

Sie können mit jeder zweiter Ordnung Typen zB:

type C = FooBar[List] 

Aber das wird nicht kompiliert:

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

Leider hat sich dies noch nicht gemacht es in TypeScript, aber es gibt ein offenes Problem dafür: https://github.com/Microsoft/TypeScript/issues/1213

+0

Bummer - upvoted das Problem. – bcherny

Verwandte Themen