在 TypeScript 中可以将强类型函数作为参数吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14638990/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are strongly-typed functions as parameters possible in TypeScript?
提问by vcsjones
In TypeScript, I can declare a parameter of a function as a type Function. Is there a "type-safe" way of doing this that I am missing? For example, consider this:
在 TypeScript 中,我可以将函数的参数声明为函数类型。是否有一种我缺少的“类型安全”的方法来做到这一点?例如,考虑这个:
class Foo {
save(callback: Function) : void {
//Do the save
var result : number = 42; //We get a number from the save operation
//Can I at compile-time ensure the callback accepts a single parameter of type number somehow?
callback(result);
}
}
var foo = new Foo();
var callback = (result: string) : void => {
alert(result);
}
foo.save(callback);
The save callback is not type safe, I am giving it a callback function where the function's parameter is a string but I am passing it a number, and compiles with no errors. Can I make the result parameter in save a type-safe function?
保存回调不是类型安全的,我给它一个回调函数,其中函数的参数是一个字符串,但我传递了一个数字,并且编译没有错误。我可以在保存类型安全函数时使用结果参数吗?
TL;DR version: is there an equivalent of a .NET delegate in TypeScript?
TL;DR 版本:在 TypeScript 中是否有等效的 .NET 委托?
回答by Ryan Cavanaugh
Sure. A function's typeconsists of the types of its argument and its return type. Here we specify that the callback
parameter's type must be "function that accepts a number and returns type any
":
当然。一个函数的类型由它的参数类型和它的返回类型组成。这里我们指定callback
参数的类型必须是“接受数字并返回类型的函数any
”:
class Foo {
save(callback: (n: number) => any) : void {
callback(42);
}
}
var foo = new Foo();
var strCallback = (result: string) : void => {
alert(result);
}
var numCallback = (result: number) : void => {
alert(result.toString());
}
foo.save(strCallback); // not OK
foo.save(numCallback); // OK
If you want, you can define a type aliasto encapsulate this:
如果需要,您可以定义一个类型别名来封装它:
type NumberCallback = (n: number) => any;
class Foo {
// Equivalent
save(callback: NumberCallback) : void {
callback(42);
}
}
回答by Drew Noakes
Here are TypeScript equivalents of some common .NET delegates:
以下是一些常见的 .NET 委托的 TypeScript 等价物:
interface Action<T>
{
(item: T): void;
}
interface Func<T,TResult>
{
(item: T): TResult;
}
回答by kbpontius
I realize this post is old, but there's a more compact approach that is slightly different than what was asked, but may be a very helpful alternative. You can essentially declare the function in-line when calling the method (Foo
's save()
in this case). It would look something like this:
我意识到这篇文章很旧,但有一种更紧凑的方法,与所要求的略有不同,但可能是一个非常有用的替代方法。您基本上可以在调用方法(在本例中为Foo
's save()
)时内联声明函数。它看起来像这样:
class Foo {
save(callback: (n: number) => any) : void {
callback(42)
}
multipleCallbacks(firstCallback: (s: string) => void, secondCallback: (b: boolean) => boolean): void {
firstCallback("hello world")
let result: boolean = secondCallback(true)
console.log("Resulting boolean: " + result)
}
}
var foo = new Foo()
// Single callback example.
// Just like with @RyanCavanaugh's approach, ensure the parameter(s) and return
// types match the declared types above in the `save()` method definition.
foo.save((newNumber: number) => {
console.log("Some number: " + newNumber)
// This is optional, since "any" is the declared return type.
return newNumber
})
// Multiple callbacks example.
// Each call is on a separate line for clarity.
// Note that `firstCallback()` has a void return type, while the second is boolean.
foo.multipleCallbacks(
(s: string) => {
console.log("Some string: " + s)
},
(b: boolean) => {
console.log("Some boolean: " + b)
let result = b && false
return result
}
)
The multipleCallback()
approach is very useful for things like network calls that may succeed or fail. Again assuming a network call example, when multipleCallbacks()
is called, behavior for both a success and failure can be defined in one spot, which lends itself to greater clarity for future code readers.
该multipleCallback()
方法对于诸如可能成功或失败的网络调用之类的事情非常有用。再次假设一个网络调用示例,当multipleCallbacks()
被调用时,成功和失败的行为都可以在一个地方定义,这有助于未来的代码阅读者更加清晰。
Generally, in my experience, this approach lends itself to being more concise, less clutter, and greater clarity overall.
一般来说,根据我的经验,这种方法有助于更简洁、更简洁、整体更清晰。
Good luck all!
祝大家好运!
回答by Krishna Ganeriwal
type FunctionName = (n: inputType) => any;
class ClassName {
save(callback: FunctionName) : void {
callback(data);
}
}
This surely aligns with the functional programming paradigm.
这肯定符合函数式编程范式。
回答by Willem van der Veen
In TS we can type functions in the in the following manners:
在 TS 中,我们可以通过以下方式键入函数:
Functions types/signatures
函数类型/签名
This is used for real implementations of functions/methods it has the following syntax:
这用于函数/方法的实际实现,它具有以下语法:
(arg1: Arg1type, arg2: Arg2type) : ReturnType
Example:
例子:
function add(x: number, y: number): number {
return x + y;
}
class Date {
setTime(time: number): number {
// ...
}
}
Function Type Literals
函数类型文字
Function type literals are another way to declare the type of a function. They're usually applied in the function signature of a higher-order function. A higher-order function is a function which accepts functions as parameters or which returns a function. It has the following syntax:
函数类型文字是另一种声明函数类型的方法。它们通常应用于高阶函数的函数签名。高阶函数是接受函数作为参数或返回函数的函数。它具有以下语法:
(arg1: Arg1type, arg2: Arg2type) => ReturnType
Example:
例子:
type FunctionType1 = (x: string, y: number) => number;
class Foo {
save(callback: (str: string) => void) {
// ...
}
doStuff(callback: FunctionType1) {
// ...
}
}
回答by Humayoun_Kabir
If you define function type first then it would be looked like
如果你先定义函数类型,那么它看起来像
type Callback = (n: number) => void;
class Foo {
save(callback: Callback) : void {
callback(42);
}
}
var foo = new Foo();
var stringCallback = (result: string) : void => {
console.log(result);
}
var numberCallback = (result: number) : void => {
console.log(result);
}
foo.save(stringCallback); //--will be showing error
foo.save(numberCallback);
Without function type by using plain property syntax it would be:
如果没有使用普通属性语法的函数类型,它将是:
class Foo {
save(callback: (n: number) => void) : void {
callback(42);
}
}
var foo = new Foo();
var stringCallback = (result: string) : void => {
console.log(result);
}
var numberCallback = (result: number) : void => {
console.log(result);
}
foo.save(stringCallback); //--will be showing error
foo.save(numberCallback);
If you want by using an interface function like c# generic delegates it would be:
如果您想使用像 c# 通用委托这样的接口函数,它将是:
interface CallBackFunc<T, U>
{
(input:T): U;
};
class Foo {
save(callback: CallBackFunc<number,void>) : void {
callback(42);
}
}
var foo = new Foo();
var stringCallback = (result: string) : void => {
console.log(result);
}
var numberCallback = (result: number) : void => {
console.log(result);
}
let strCBObj:CallBackFunc<string,void> = stringCallback;
let numberCBObj:CallBackFunc<number,void> = numberCallback;
foo.save(strCBObj); //--will be showing error
foo.save(numberCBObj);
回答by cancerbero
Besides what other said, a common problem is to declare the types of the same function that is overloaded. Typical case is EventEmitter on() method which will accept multiple kind of listeners. Similar could happen When working with redux actions - and there you use the action type as literal to mark the overloading, In case of EventEmitters, you use the event name literal type:
除了其他人所说的,一个常见的问题是声明重载的同一函数的类型。典型的例子是 EventEmitter on() 方法,它将接受多种类型的监听器。使用 redux 操作时可能会发生类似的情况 - 在那里您使用操作类型作为文字来标记重载,在 EventEmitters 的情况下,您使用事件名称文字类型:
interface MyEmitter extends EventEmitter {
on(name:'click', l: ClickListener):void
on(name:'move', l: MoveListener):void
on(name:'die', l: DieListener):void
//and a generic one
on(name:string, l:(...a:any[])=>any):void
}
type ClickListener = (e:ClickEvent)=>void
type MoveListener = (e:MoveEvent)=>void
... etc
// will type check the correct listener when writing something like:
myEmitter.on('click', e=>...<--- autocompletion