假设我们有像ramda.assoc(http://ramdajs.com/docs/#assoc)
这样的关联函数此功能用于设置对象的属性。因此,我们希望使用一个属性名称参数为函数变量进行打字。
该函数接受一个参数属性名称并返回一个curried函数,该函数可能需要一个或两个参数:
如果它需要两个参数(值和对象),它会在属性上设置值 对象并返回属性设置为value的已修改对象。
如果它需要一个参数(值),则返回一个需要修改对象的函数。
是否可以进行一些打字,以便TS可以处理这两种情况?这是我的看法,但它不起作用:
interface Assoc {
// we may describe both signatures but only first will work
(prop: string): <T, U>(val: T, obj: U) => U;
(prop: string): <T>(val: T) => <U>(obj: U) => U;
}
// implementation
const assoc: Assoc = (prop: string): any => {
....
}
// then there is two function for testing both cases
// this one expects function with one arg that returns function
const map = (func: (some: string) => (x: number) => 1) => {
}
// this one expects function with two args that returns value
const map2 = (func: (some: string, other: string) => 1) => {
}
map(assoc('xxx')) // gives an error
map2(assoc('xxx')) //works ok
我希望两者兼顾。
答案 0 :(得分:1)
我不认为这是可能的 两个签名都需要相同的参数,因此编译器无法推断出要采用的签名,第一个签名可能是默认行为。
这很有道理,因为当编译器认为你可能犯了错误时,他会试图照顾你并且错误。
在这种情况下,编译器没有足够的信息来知道您是否正确,因为assoc
可以仅根据两种情况下相同的输入返回不同类型。
如果您尝试在打字稿中为这样的方法编写实现,编译器就不会让您:
function fn(base: number): (a: number) => number;
function fn(base: number): (a: number, b: number) => string;
function fn(base: number) { // Error: No best common type exists among return expressions
if (base < 10) {
return (a: number) => base * a;
}
return (a: number, b: number) => "";
}
但是如果您正在使用正在执行此操作的js库,那么您可以通过断言来告诉编译器您知道自己在做什么:
type Assoc1 = (prop: string) => <T, U>(val: T, obj: U) => U;
type Assoc2 = (prop: string) => <T>(val: T) => <U>(obj: U) => U;
type Assoc = Assoc1 | Assoc2;
const assoc: Assoc = (prop: string) => {
return null;
}
const map = (func: (some: string) => (x: number) => number) => {}
const map2 = (func: (some: string, other: string) => string) => {}
map((assoc as Assoc2)('xxx'));
map2((assoc as Assoc1)('xxx'));
它不那么优雅,但我很确定你无法绕过它。
如果有人能想出办法,我很乐意看到它。
答案 1 :(得分:0)
@ nitzan-托默
你知道,似乎有更好的解决方案:
interface CurriedFunction {
<T1, T2, R>(t1: T1, t2: T2): R;
<T1>(t1: T1): <T2, R>(t2: T2) => R;
}
interface Assoc {
(prop: string): CurriedFunction
}
对此主题进行了很好的讨论:https://gist.github.com/donnut/fd56232da58d25ceecf1