2015-12-08 2 views
2

У меня есть следующее определение каррированной функции в машинописном:Тип вывода в машинописном для кэрри функции

interface Curried2<A, B, Z> { 
    (_0: A): (_0: B) => Z; 
    (_0: A, _1: B): Z; 
} 

У меня есть следующая функция, которая должна принять функцию (кэрри или нет):

function apply<T, U>(f: (_0: T) => U, x: T): U { 
    return f(x); 
} 

Теперь, учитывая

let curried: Curried2<number, boolean, string> = ... 

следующих работ (как и ожидалось):

apply<number, (_0: boolean) => string>(curried, 4); 

Но машинопись не может определить тип по себе:

apply(curried, 4); 

(Даже если есть только одна перегрузка для () которая принимает одно значение.) Он жалуется:

Argument of type 'Curried2<number, boolean, string>' is not assignable to parameter of type '(_0: number) => string' ...
Она правильно inferred T, но выведено U будет string. Почему это? Что я могу сделать, чтобы сделать работу типа для меня в этом случае (поскольку явно указано T и U слишком многословно для моего вкуса)?

Заранее благодарен!

ответ

0

Я мог бы попробовать этот подход:

type Curried<T1, T2, T3> = (x: T1) => (y: T2) => T3; 

function apply<T, U>(f: (value: T) => U, x: T): U { 
    return f(x); 
} 

//simple demo 
var someFunc: Curried<string, number, [string, number]> = x => y => [x, y]; 
var curriedSomeFunc = apply(someFunc, "string here"); 
var result1 = curriedSomeFunc(0); //will be ["string here", 0] 
var result2 = curriedSomeFunc(1); //will be ["string here", 1] 

еще одну попытку. Синтаксис является правильным, но не безопасности, если вы не пройдете не правильную функцию для выделки:

interface Curried<T1, T2, T3> { 
    (x: T1, y: T2): T3; 
    (x: T1): (y: T2) => T3 
} 

let f1 = <Curried<string, number, [string, number]>> 
    ((x: string, y: number) => [x, 1]); 
let f2 = <Curried<string, number, [string, number]>> 
    ((x: string) => (y: number) => [x, y]); 

function apply<T, V>(f: (x: T) => V, x: T): V { 
    return f(x); 
} 

let curriedF1 = apply(f1, "42"); //Won't work (no function to curry) but type inference is OK 
let curriedF2 = apply(f2, "11"); //Will work and type inference is also OK 
+0

В этом случае я бы потерять возможность использовать функцию в качестве обычного неработающая функция, так что это не сработает, к сожалению :( –

+0

Вот и все! Единственное различие между вашим примером (в котором работает вывод типа) и моим (в котором это не так) - это порядок перегруженных методов 'Curried 'Любая идея, почему это так? –

+0

Теперь следующее не будет работать:' function applyTwo (f: (x: S, y: T) => V, x: S, y: T): V {return f (x, y); }; applyTwo (f1, "23", 23); 'Что, как вы думаете, является причиной этого? –

0

Следующая теперь работает:

interface F1<A, Z> { 
    (_0: A): Z; 
} 

interface F2<A, B, Z> extends F1<A, F1<B, Z>> { 
    (_0: A, _1: B): Z; 
} 

function apply<T, U>(f: F1<T, U>, x: T): U { 
    return f(x); 
} 

function apply2<T, U, V>(f: F2<T, U, V>, x: T, y: U): V { 
    return f(x, y); 
} 

let curried: F2<number, boolean, string> = null; 

const x: F1<boolean, string> = apply(curried, 4); 
const y: string = apply2(curried, 4, false); 
Смежные вопросы