2016-04-27 2 views
15

Скажем, у меня есть интерфейс A:Как это выразить в машинописном тексте?

interface A { 
    foo: number 
    bar: string 
} 

И у меня есть общий тип Option:

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

Затем я создаю новый интерфейс B из A и Option:

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

Как сделать эту операцию более общей? То есть. API я хочу это:

type B = Lift<A> 

Где Lift автоматически отображает каждый член A к Option. Обратите внимание, что A может иметь любое количество элементов любого типа.

Как я могу реализовать Lift? Если это невозможно в TypeScript, у кого-нибудь есть решение Scala/Haskell?

ответ

2

Хорошие новости: с TypeScrip т 2.1.0, теперь это возможно с помощью 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 } } 

Противоположное также возможно:

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

Отображаемые типы супер крутые - спасибо за ответ. – bcherny

4

Я не смотрел TypeScript на некоторое время (я думаю, что это было вокруг версии 1.0), поэтому я не могу сказать, есть ли он сейчас.

Для чего требуется системная функция типа, называемая более высокими типами; он позволяет строить типы, передавая их в качестве аргументов для конструкторов типов, очень похожих на функциональное приложение, поднятых до уровня типа.

Вам нужно будет отрегулировать определение A, чтобы сделать эту работу. Вот как я бы добиться того, чего вы хотите в 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

Вы ищете higher-kinded types. Здесь в Scala:

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

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

Вы можете использовать любой второго порядка типов, например:

type C = FooBar[List] 

Но это не компилируется:

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

К сожалению, это еще не сделано это в TypeScript, но для него есть открытая проблема: https://github.com/Microsoft/TypeScript/issues/1213

+0

Лентяй - upvoted вопрос. – bcherny