Typescript 泛型函数中的默认参数
我有一个带有签名的函数Typescript 泛型函数中的默认参数,typescript,Typescript,我有一个带有签名的函数zip: function zip<T, U, V>(ts: T[], us: U[], zipper: (t: T, u: U) => V): V[] 这会产生(某种程度上预期的)编译错误,即(T,U)=>[T,U]不能分配给(T,U)=>V 最后,我用一组有点难看的重载解决了这个问题: export function zip<T, U>(ts: T[], us: U[]): [T, U][] export function zip<
zip
:
function zip<T, U, V>(ts: T[], us: U[], zipper: (t: T, u: U) => V): V[]
这会产生(某种程度上预期的)编译错误,即(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(ts:T[],us:U[]):[T,U][]
导出函数zip(
ts:T[],
美国:U[],
拉链:(t:t,u:u)=>V
):V[]
导出函数zip(
ts:T[],
美国:U[],
拉链:(t:t,u:u)=>[t,u]=(t,u)=>[t,u]
):[T,U][]{
/* ... */
}
这种方法有两个问题:
zip(T[],U[]):[T,U][
被呈现两次(第一次重载和实现本身)李>
有没有更好的方法来满足我的要求?第一次尝试时出现的错误是否是编译器错误(似乎不是,但如果是,肯定会使解决方案更简单)?您可以限制
V
function zip<T, U, V extends [T, U]>(
ts: T[],
us: U[],
zipper: (t: T, u: U) => V = (t, u) => (<V>[t, u])
)
您可以限制您的
V
function zip<T, U, V extends [T, U]>(
ts: T[],
us: U[],
zipper: (t: T, u: U) => V = (t, u) => (<V>[t, u])
)
这个错误是好的;泛型类型参数由函数的调用者指定,而不是由实现者指定。TypeScript很乐意推断参数,并使开发人员不用指定它们,但它们仍然是根据调用者的需要而不是实现者的需要推断出来的。这意味着无论谁调用
zip()
,都可以选择他们想要的T
、U
和V
。TypeScript正确地警告您,函数的实现不能假定V
将与[T,U]
兼容。使用原始签名和默认参数,调用者可以自由调用zip([“a”],[1])
。是的,这太疯狂了,不,你不能实现它。因此,编译器正在帮助您解决警告问题
重载是解决此问题的合理方法。你的签名很好。至于实现签名,是的,您应该使其更通用,记住
zippers
参数必须是可选的。但是,请注意,您必须声明默认的zipper
返回一个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, V>(
ts: T[],
us: U[],
zipper?: (t: T, u: U) => V // note the question mark
): V[] {
if (!zipper) {
zipper = (t, u) => ([t, u] as any as V); // note the assertion
}
const ret: V[] = []
const len = Math.min(ts.length, us.length);
for (let i = 0; i < len; i++) {
ret.push(zipper(ts[i], us[i]));
}
return ret;
}
导出函数zip(ts:T[],us:U[]):[T,U][]
导出函数zip(
ts:T[],
美国:U[],
拉链:(t:t,u:u)=>V
):V[]
导出函数zip(
ts:T[],
美国:U[],
拉链?:(t:t,u:u)=>V//注意问号
):V[]{
如果(!拉链){
zippers=(t,u)=>([t,u]与V一样);//注意断言
}
常数ret:V[]=[]
常数len=数学最小值(ts.length,us.length);
for(设i=0;i
这基本上就是TypeScript中重载的情况。编译器在检查实现时并不真正理解重载的签名。一旦使用重载,您就告诉编译器您将负责确保实现是安全的
无论如何,希望这有帮助;祝你好运 这是一个很好的错误;泛型类型参数由函数的调用者指定,而不是由实现者指定。TypeScript很乐意推断参数,并使开发人员不用指定它们,但它们仍然是根据调用者的需要而不是实现者的需要推断出来的。这意味着无论谁调用
zip()
,都可以选择他们想要的T
、U
和V
。TypeScript正确地警告您,函数的实现不能假定V
将与[T,U]
兼容。使用原始签名和默认参数,调用者可以自由调用zip([“a”],[1])
。是的,这太疯狂了,不,你不能实现它。因此,编译器正在帮助您解决警告问题
重载是解决此问题的合理方法。你的签名很好。至于实现签名,是的,您应该使其更通用,记住
zippers
参数必须是可选的。但是,请注意,您必须声明默认的zipper
返回一个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, V>(
ts: T[],
us: U[],
zipper?: (t: T, u: U) => V // note the question mark
): V[] {
if (!zipper) {
zipper = (t, u) => ([t, u] as any as V); // note the assertion
}
const ret: V[] = []
const len = Math.min(ts.length, us.length);
for (let i = 0; i < len; i++) {
ret.push(zipper(ts[i], us[i]));
}
return ret;
}
导出函数zip(ts:T[],us:U[]):[T,U][]
导出函数zip(
ts:T[],
美国:U[],
拉链:(t:t,u:u)=>V
):V[]
导出函数zip(
ts:T[],
美国:U[],
拉链?:(t:t,u:u)=>V//注意问号
):V[]{
如果(!拉链){
zippers=(t,u)=>([t,u]与V一样);//注意断言
}
常数ret:V[]=[]
常数len=数学最小值(ts.length,us.length);
for(设i=0;i
这基本上就是TypeScript中重载的情况。编译器在检查实现时并不真正理解重载的签名。一旦使用重载,您就告诉编译器您将负责确保实现是安全的
无论如何,希望这有帮助;祝你好运 将
V
限制为[T,U]
会对功能界面造成不必要的限制,但不会造成任何运行时危害。将V
限制为[T,U]
会对功能界面造成不必要的限制,而不会造成任何运行时危害。