我的函数zip
有签名:
function zip<T, U, V>(ts: T[], us: U[], zipper: (t: T, u: U) => V): V[]
我正在尝试为zipper
参数指定默认值(t, u) => [t, u]
:
function zip<T, U, V>(
ts: T[],
us: U[],
zipper: (t: T, u: U) => V = (t, u) => (<[T, U]>[t, u])
)
产生(有些预期)关于(T, U) => [T, U]
无法分配给(T, U) => V
的编译错误。
最后,我用一些丑陋的重载解决了这个问题:
export function zip<T, U>(ts: T[], us: U[]): [T, U][]
export function zip<T, U, V>(
ts: T[],
us: U[],
zipper: (t: T, u: U) => V
): V[]
export function zip<T, U>(
ts: T[],
us: U[],
zipper: (t: T, u: U) => [T, U] = (t, u) => [t, u]
): [T, U][] {
/* ... */
}
这种方法有两个问题:
zip(T[], U[]): [T, U][]
被呈现两次(第一次重载和实现本身); 有没有更好的方法来做我想要的事情?在第一次尝试中是错误的编译器错误(似乎不是,但如果它确实使解决方案变得更简单)?
答案 0 :(得分:3)
错误很好;泛型类型参数由函数的调用者指定,而不是实现者。 TypeScript很乐意推断参数并减轻开发人员的指定,但仍然可以根据调用者的需求推断出它们,而不是实现者。这意味着,只有拨打params$logo_path
的人才可以选择他们想要的zip()
,T
和U
。 TypeScript正确地警告您,函数的实现不能假定V
将与V
兼容。使用原始签名和默认参数,呼叫者可以免费呼叫[T, U]
。是的,这很疯狂,不,你不能实现它。所以编译器正在帮你解决警告。
重载是此问题的合理解决方案。你的过载签名很好。至于实现签名,是的,您应该使它更通用,请记住zip<string, number, boolean>(["a"],[1])
参数必须是可选的。但请注意,您必须断言默认zipper
返回zipper
,因为编译器仍然不能保证基于实现签名是真的(即使你知道它是安全的,因为重载限制了可以进行的调用)。这是一个例子:
V
这基本上是TypeScript中的重载。在检查实现时,编译器并不真正理解重载的签名。一旦你使用重载,你告诉编译器你将负责确保实现是安全的。
无论如何,希望有所帮助;祝你好运!
答案 1 :(得分:0)
您可以限制V
。
function zip<T, U, V extends [T, U]>(
ts: T[],
us: U[],
zipper: (t: T, u: U) => V = (t, u) => (<V>[t, u])
)
或转为any
。
function zip<T, U, V>(
ts: T[],
us: U[],
zipper: (t: T, u: U) => V = (t, u) => (<V><any>[t, u])
)