Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 如果作为参数传递,函数签名不会自动加宽_Typescript_Type Conversion_Signature - Fatal编程技术网

Typescript 如果作为参数传递,函数签名不会自动加宽

Typescript 如果作为参数传递,函数签名不会自动加宽,typescript,type-conversion,signature,Typescript,Type Conversion,Signature,我试图创建一个高阶函数,它接受许多具有特定签名的函数。在本例中,签名是只接受一个实现特定接口的参数的任何函数。说,Foo: 接口Foo{ foo:string } 函数higherOrderStuff(funs:((foo:foo)=>void)[]{ //做高阶的工作 } 但是,为了便于类型检查,有些函数使用原始接口的交点。像这样: 键入MyFoo=Foo&{ 福:“酒吧” }; 函数myFunction(foo:MyFoo){ //做我的事 } 不幸的是,将这些函数传递给高阶包装会产生错

我试图创建一个高阶函数,它接受许多具有特定签名的函数。在本例中,签名是只接受一个实现特定接口的参数的任何函数。说,
Foo

接口Foo{
foo:string
}
函数higherOrderStuff(funs:((foo:foo)=>void)[]{
//做高阶的工作
}
但是,为了便于类型检查,有些函数使用原始接口的交点。像这样:

键入MyFoo=Foo&{
福:“酒吧”
};
函数myFunction(foo:MyFoo){
//做我的事
}
不幸的是,将这些函数传递给高阶包装会产生错误:

higherOrderStuff([myFunction]);//编译错误
错误是正确的:
Foo
不能分配给
MyFoo
。事实上,我这样做是有原因的

更奇怪的是,如果我尝试了一些不同的东西,并传递了函数以外的任何东西,那么同样的场景也会像预期的那样工作

函数dostufwithfoos(foos:Foo[]){
//做事
}
常量myFoo:myFoo={foo:'bar'};
dostufwithfoos([myFoo]);//没有弯弯曲曲的线条
那么,为什么参数被正确地加宽了,而函数参数的参数却没有

显式强制转换修复了错误,但我似乎不需要它

higherOrderStuff([myFunction as(foo:foo)=>void]);//这很有效

编译器错误的发生是因为函数的参数类型是反变的,这基本上意味着,如果传递的函数的参数类型为
T
,则不能传递的函数的参数类型为
T
(不过,超类型也可以)

作为代码中的一个示例,假设您通过向
funs
中的每个函数传递对象
{foo:'not bar'}
来实现
higherOrderStuff

interface Foo {
  foo: string
}

function higherOrderStuff(funs: ((foo: Foo) => void)[]) {
  return funs.map(f => f({foo: 'not-bar'}))
}
由于以下原因,
MyFoo
具有较窄的类型
{foo:bar}

type MyFoo = Foo & {
  foo: 'bar'
};
您可以定义一个
myFunction
,该函数取决于其参数具有以下较窄的类型:

function myFunction(foo: MyFoo) {
  const shouldBeBar = foo.foo // inferred type: 'bar'
  const barObject = {bar: () => 42}
  const barFunction = barObject[shouldBeBar]
  return barFunction() // should return 42
}
所有内容的类型仍然正确,并且由于
shouldbebebar
只能是
bar
barFunction
将是一个返回42的函数

但是如果你现在跑

console.log(higherOrderStuff([myFunction]))
它将调用
myFunction({foo:'notbar'})
,这将导致
barFunction
undefined
结束,并引发运行时错误

这就是类型错误试图防止发生的情况

为了理解协变和逆变,水果和果汁机的类比可能会有所帮助

如果你要一片水果,可以得到一个亚型的橘子,而如果你要一个橘子,你不只是想得到任何种类的水果。这是协方差


现在你需要一个普通的榨汁机(即水果到果汁的一个功能),那么买一个橙汁榨汁机是不好的,因为你可能也想要菠萝汁。另一方面,如果你要一台橙汁机,普通的果汁机也可以。你可以说榨汁机榨汁的东西的类型是反变的。

编译器错误的发生是因为函数的参数类型是反变的,这基本上意味着如果你传递的函数采用的是
T
类型的参数,您不能传递一个采用子类型
t
的参数的函数(尽管是超类型也可以)

作为代码中的一个示例,假设您通过向
funs
中的每个函数传递对象
{foo:'not bar'}
来实现
higherOrderStuff

interface Foo {
  foo: string
}

function higherOrderStuff(funs: ((foo: Foo) => void)[]) {
  return funs.map(f => f({foo: 'not-bar'}))
}
由于以下原因,
MyFoo
具有较窄的类型
{foo:bar}

type MyFoo = Foo & {
  foo: 'bar'
};
您可以定义一个
myFunction
,该函数取决于其参数具有以下较窄的类型:

function myFunction(foo: MyFoo) {
  const shouldBeBar = foo.foo // inferred type: 'bar'
  const barObject = {bar: () => 42}
  const barFunction = barObject[shouldBeBar]
  return barFunction() // should return 42
}
所有内容的类型仍然正确,并且由于
shouldbebebar
只能是
bar
barFunction
将是一个返回42的函数

但是如果你现在跑

console.log(higherOrderStuff([myFunction]))
它将调用
myFunction({foo:'notbar'})
,这将导致
barFunction
undefined
结束,并引发运行时错误

这就是类型错误试图防止发生的情况

为了理解协变和逆变,水果和果汁机的类比可能会有所帮助

如果你要一片水果,可以得到一个亚型的橘子,而如果你要一个橘子,你不只是想得到任何种类的水果。这是协方差


现在你需要一个普通的榨汁机(即水果到果汁的一个功能),那么买一个橙汁榨汁机是不好的,因为你可能也想要菠萝汁。另一方面,如果你要一台橙汁机,普通的果汁机也可以。你可以说榨汁机榨汁的东西类型是相反的。

你能推荐一篇关于协方差和逆变的文章或书吗?这对我来说很神奇,我只是凭直觉理解level@captain-不幸的是,我从来没有找到一个很好的解释。通常它们相当抽象或过于冗长。这个还行:谢谢,我已经读过这篇文章了,甚至在我的书签里都有)谢谢你的详细回答。我不知道协方差。现在它变得更有意义了。但是,如果基于我的要求,我认为对冲检查妨碍了我的工作,是否可以在高阶函数上禁用它们,而不是在参数级别(使用强制转换)解决问题?我希望保留“strictFunctionTypes”标志,因为这通常是理想的行为。如果话题太大,无法发表评论,我愿意开始一个新问题section@fedetibaldo我还想到一件事:你也可以