我有以下ts函数:
const fnGeneric = <V,I>(fn:<U>(param:U) => V, param:I) => fn(param);
const fn = (some:string) => some;
const result = fnGeneric(fn,5);
但结果以静态类型错误结尾:
类型参数'(某些:字符串)=>字符串'不能分配给类型参数'(参数:U)=>字符串'。 参数类型'some'和'param'不兼容。 不能将'U'类型分配给'string'
此模式有什么问题?我认为您应该推断我输入的是数字,但是这里有一些空格。
答案 0 :(得分:0)
我可以给您一个更现实的场景,我制作了fn的简化版本,这是真实的:
export const inject = <I,V>(fn:<U>(input?:U) => V, resolveWithPayload: boolean, resolveArgs?: I) => <R>(payload:R):R => {
resolveWithPayload ? fn(payload) : resolveArgs ? fn(resolveArgs) : fn();
return payload;
};
const fn = (value:number):number => {
propertyToMutate = value;
return propertyToMutate;
}
const res =_fish.inject(fn,false,60)(50);
但调用它以:
结尾类型参数'(值:数字)=>数字'不能分配给类型参数'(输入?:U)=>数字'。 参数``值''和``输入''的类型不兼容。 不能将'U'类型分配给'数字'类型。
如果我通过您的方式改进代码:
export const inject = <I,V,U>(fn:(input?:U) => V, resolveWithPayload: boolean, resolveArgs?: I) => <R>(payload:R):R => {
resolveWithPayload ? fn(payload) : resolveArgs ? fn(resolveArgs) : fn();
return payload;
};
以类型定义错误结束,注入本身如下:
TS2345:类型'R'的参数不能分配给类型的参数 “ U”。
TS2345:类型'I'的参数不能分配给类型的参数 “ U”。
答案 1 :(得分:0)
我认为您的定义已关闭,不会自动推断出适合您意图的类型。这是我要使用的定义:
const fnGeneric = <V,U>(fn: (param:U) => V, param: U) => fn(param);
const fn = (some: string) => some;
const result = fnGeneric(fn, 5);
这在函数和第二个参数中使用相同的类型参数U
,以确保它们的兼容性。当然,该调用将无效,因为fn
仅接受字符串作为参数。
答案 2 :(得分:0)
如果您查看 fnGeneric
的类型签名,就像它出现在 .d.ts
文件中一样,其原因会变得更加清楚。
declare const fnGeneric: <V,I>(fn:<U>(param:U) => V, param:I) => V
与 U
和 I
没有任何关系。以下是类型检查器可以从该签名推断出的内容:
fnGeneric
是一个为所有类型定义的函数V
和I
,接收2个参数fn
和param
和返回类型 V
fn
是一个为所有类型定义的函数U
接收1个参数param
,类型为U
并返回V
param
的类型为 I
这种类型检查很好,因为 fn
是一个可以将任何类型转换为 V
的函数,因此在定义 I
中传递一个 fn(param)
是完美的可以接受。
当您尝试调用此函数时,问题就开始了。为了调用fnGeneric
,你需要给出一个可以接受任何类型的函数,并将它变成你想从fnGeneric
中取出的类型。这是不可能的!在您的示例中传递 const fn: (some: string) => string
不起作用,因为 fn
不接受任何类型,它只接受字符串。签名必须是 const fn: <U>(some: U) => string
。因此错误:
'(some: string) => string' 类型的参数不能分配给 '(param: U) => string' 类型的参数。参数“some”和“param”的类型不兼容。类型 'U' 不能分配给类型 'string
此外,根据您的示例 fnGeneric(fn, 5)
,您正试图通过 强制 number
将 string
传递给采用 fn
成为一个接受任何类型参数的函数。这是一个类型检查的代码片段:
const fnGeneric = <A>(fn: <B>(param: B) => B, param: A): A => fn(param);
const fn = <A>(some: A): A => some;
const result: number = fnGeneric(fn, 5); // result = 5
fn
在这个例子中通常被称为 identity
函数 - 它返回给定的参数,它是具有签名的函数的唯一有效实现(没有任意类型转换) <A>(a: A) => A
。通过扩展,fnGeneric
是一个函数,它接受恒等函数和任何类型的参数,并将恒等函数的应用返回给该参数。
这种模式有什么问题?
定义的fnGeneric
没有任何意义,编写一个满足签名的类型检查的程序是不可能的。使类型工作的唯一方法只是使它变得多余。没有任何情况下最好调用 fnGeneric(identity, x)
而不是只调用 identity(x)
(或者就此而言,只是表达式 x
)。它们都是完全等效的。