[英]Typescript generic infer of nested function
I have these ts function:我有这些 ts 功能:
const fnGeneric = <V,I>(fn:<U>(param:U) => V, param:I) => fn(param);
const fn = (some:string) => some;
const result = fnGeneric(fn,5);
but result ends with static type error :但结果以静态类型错误结束:
Argument of type '(some: string) => string' is not assignable to parameter of type '(param: U) => string'.
'(some: string) => string' 类型的参数不能分配给 '(param: U) => string' 类型的参数。 Types of parameters 'some' and 'param' are incompatible.
参数“some”和“param”的类型不兼容。 Type 'U' is not assignable to type 'string
类型 'U' 不能分配给类型 'string
What is wrong with this pattern?这种模式有什么问题? I think U should infer I type as number, but I have some blank space here.
我想你应该推断我输入的是数字,但我这里有一些空格。
I think your definition is off, the types will not be inferred automatically to fit your intent.我认为您的定义已关闭,不会自动推断类型以符合您的意图。 This is the definition i would use:
这是我将使用的定义:
const fnGeneric = <V,U>(fn: (param:U) => V, param: U) => fn(param);
const fn = (some: string) => some;
const result = fnGeneric(fn, 5);
This uses the same type parameter U
both in the function and the second argument, ensuring their compatibility.这在函数和第二个参数中使用相同的类型参数
U
,确保它们的兼容性。 Of course the call will be invalid then, because fn
only accepts strings as argument.当然调用将是无效的,因为
fn
只接受字符串作为参数。
The reason for this becomes more clear if you look at the type signature of fnGeneric
as it would appear in a .d.ts
file.如果您查看
fnGeneric
的类型签名,就像它出现在.d.ts
文件中一样,其原因就会变得更加清楚。
declare const fnGeneric: <V,I>(fn:<U>(param:U) => V, param:I) => V
Does not relate U
and I
in any way.不以任何方式将
U
和I
联系起来。 Here is what the type checker can infer from this signature:以下是类型检查器可以从该签名中推断出的内容:
fnGeneric
is a function defined for all types V
, and I
, receiving 2 parameters fn
and param
and returning the type V
fnGeneric
是为所有类型V
和I
定义的函数,接收 2 个参数fn
和param
并返回类型V
fn
is a function defined for all types U
receiving 1 parameter param
, of type U
and returning V
fn
是为所有类型U
定义的函数,接收 1 个参数param
,类型U
并返回V
param
is of type I
param
是I
型This type-checks fine, because fn
is a function that can turn any type into a V
, so passing it an I
in the definition fn(param)
is perfectly acceptable.这种类型检查很好,因为
fn
是一个可以将任何类型转换为V
的函数,因此在定义fn(param)
传递一个I
是完全可以接受的。
The problems start when you try to call this function.当您尝试调用此函数时,问题就开始了。 In order to call
fnGeneric
, you need to give is a function that can take any type , and turn it into the type you want to get out of fnGeneric
.为了调用
fnGeneric
,你需要给出一个可以接受任何类型的函数,并将它变成你想要从fnGeneric
取出的fnGeneric
。 This is impossible!这是不可能的! Passing in a
const fn: (some: string) => string
like in your example doesn't work, becase fn
doesn't accept any type, it only accepts strings.传入一个
const fn: (some: string) => string
就像在你的例子中一样不起作用,因为fn
不接受任何类型,它只接受字符串。 The signature would need to be const fn: <U>(some: U) => string
.签名需要是
const fn: <U>(some: U) => string
。 Hence the error:因此错误:
Argument of type '(some: string) => string' is not assignable to parameter of type '(param: U) => string'.
'(some: string) => string' 类型的参数不能分配给 '(param: U) => string' 类型的参数。 Types of parameters 'some' and 'param' are incompatible.
参数“some”和“param”的类型不兼容。 Type 'U' is not assignable to type 'string
类型 'U' 不能分配给类型 'string
Additionally, based on your example fnGeneric(fn, 5)
, you are trying to pass a number
to a function that takes a string
by coercing fn
to be a function that takes any type of argument.此外,根据您的示例
fnGeneric(fn, 5)
,您试图通过将fn
强制为采用任何类型参数的函数,将number
传递给采用string
的函数。 Here is a code snippet that type checks:这是一个类型检查的代码片段:
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
in this example is commonly known as the identity
function - which returns the parameter it is given, and it is the only valid implementaion (without arbitrary type casting) of a function with the signature <A>(a: A) => A
.这个例子中的
fn
通常被称为identity
函数——它返回给定的参数,它是具有签名<A>(a: A) => A
的函数的唯一有效实现(没有任意类型转换) . By extension, fnGeneric
is a function that takes the identity function and a parameter of any type, and returns the application of the identity function to that parameter.通过扩展,
fnGeneric
是一个函数,它接受恒等函数和任何类型的参数,并将恒等函数的应用返回给该参数。
What is wrong with this pattern?
这种模式有什么问题?
fnGeneric
as defined doesn't make any sense, it would be impossible to write a program that type checks that satisfies the signature.定义的
fnGeneric
没有任何意义,编写满足签名的类型检查的程序是不可能的。 The only way to make the types work simply makes it redundant.使类型工作的唯一方法只是使它变得多余。 There aren't any cases where it would be preferable to call
fnGeneric(identity, x)
instead of just identity(x)
(or for that matter, simply the expression x
).没有任何情况下最好调用
fnGeneric(identity, x)
而不是identity(x)
(或者就此而言,只是表达式x
)。 They are all completely equivalent.它们都是完全等效的。
i can give u more realistic scenario, i made simplier version of fn, there is real:我可以给你更真实的场景,我制作了更简单的 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);
but calling it ends with :但调用它以:
Argument of type '(value: number) => number' is not assignable to parameter of type '(input?: U) => number'.
“(value: number) => number”类型的参数不能分配给“(input?: U) => number”类型的参数。 Types of parameters 'value' and 'input' are incompatible.
参数“值”和“输入”的类型不兼容。 Type 'U' is not assignable to type 'number'.
“U”类型不能分配给“数字”类型。
if i improve code by your way:如果我按照你的方式改进代码:
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; };
it ends by type definition error in inject itself like:它以注入自身的类型定义错误结束,例如:
TS2345: Argument of type 'R' is not assignable to parameter of type 'U'.
TS2345:“R”类型的参数不能分配给“U”类型的参数。
TS2345: Argument of type 'I' is not assignable to parameter of type 'U'.
TS2345:“I”类型的参数不能分配给“U”类型的参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.