2016-04-27 16 views
15

Diciamo che avere un'interfaccia A:Come si esprime in Typescript?

interface A { 
    foo: number 
    bar: string 
} 

e ho un tipo generico Option:

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

Poi ho creare una nuova interfaccia B da A e Option:

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

Come posso rendere questa operazione più generale? Vale a dire. L'API che voglio è:

type B = Lift<A> 

Dove Lift mappa automaticamente ogni membro del A a un Option. Si noti che A può avere un numero qualsiasi di membri, di qualsiasi tipo.

Come posso implementare Lift? Se questo non è possibile in TypeScript, qualcuno ha una soluzione Scala/Haskell?

risposta

2

Buone notizie: con TypeScrip t 2.1.0, questo è ora possibile tramite 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 } } 

L'opposto è inoltre possibile:

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

I tipi di mapping sono fantastici - grazie per la risposta. – bcherny

4

Non ho guardato TypeScript per un po '(penso che fosse intorno alla versione 1.0), quindi non posso davvero dire se è lì ora.

Ciò che si desidera è una funzionalità di sistema di tipi denominata di tipo più elevato; consente di costruire tipi passandoli come argomenti per digitare costruttori, molto simili all'applicazione di funzioni, sollevati al livello del tipo.

Dovrai modificare la definizione di A per farlo funzionare. Ecco come mi piacerebbe ottenere quello che vuoi in Haskell:

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

Siete alla ricerca di higher-kinded types. Qui è 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] 

È possibile utilizzare qualsiasi secondo ordine i tipi ad esempio:

type C = FooBar[List] 

Ma questi non si compila:

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

Purtroppo, questo non è ancora fatta in TypeScript ma esiste un problema aperto: https://github.com/Microsoft/TypeScript/issues/1213

+0

Bummer - Upvoted il problema. – bcherny