2013-02-01 66 views
292

在TypeScript中,我可以将函数的参数声明为Function类型。有没有一种“类型安全”的做法,我失踪了?例如,考虑一下:在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); 

保存回调不是类型安全的,我给它一个回调函数,其中该函数的参数是一个字符串,但我传递了一个数字,并没有错误编译。我可以使结果参数保存为类型安全函数吗?

tl; dr版本:是否有相当于TypeScript中的.NET代理?

回答

427

肯定的:

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 

如果你愿意,你可以定义一个类来封装此:

type NumberCallback = (n: number) => any; 

class Foo { 
    // Equivalent 
    save(callback: NumberCallback) : void { 
     callback(42); 
    } 
} 
+1

呵呵,现在看起来很明显。谢谢! – vcsjones

+4

'''(n:number)=> any'''表示任何函数签名? –

+7

@nikkwong它意味着函数带有一个参数('数字'),但返回类型根本不受限制(可以是任何值,甚至是'void') –

62

下面是一些常见的.NET代表的打字稿当量:

interface Action<T> 
{ 
    (item: T): void; 
} 

interface Func<T,TResult> 
{ 
    (item: T): TResult; 
} 
+0

看起来很有用,但它实际上会使用这种类型的反模式。无论如何,这些看起来比C#代表更像Java SAM类型。当然,他们不是,他们相当于类型别名形式,它只是更加优雅的功能 –

+3

@AluanHaddad你能否详细说明为什么你会认为这是一个反 模式? –

+3

原因是TypeScript有一个简洁的函数类型文字语法,可以避免使用这种界面。在C#中,委托是名义上的,但Action和Func委托都可以避免对特定委托类型的大部分需求,并且有趣的是,给C#带来了结构化类型的外观。这些代表的缺点是他们的名字没有任何意义,但其他优势通常超过了这一点。在TypeScript中,我们不需要这些类型。所以反模式将是'函数图(xs:T [],f:Func )'。首选函数图(xs:T [],f:(x:T)=> U)' –

6

我意识到这篇文章是旧的,但有一个更紧凑的方法,是比要求略有不同,埠t可能是一个非常有用的选择。在调用方法时,您基本上可以声明函数(在这种情况下为Foosave())。这将是这个样子:

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 
    } 
) 

multipleCallback()方法是对于像网络电话,可能成功也可能失败非常有用的。再次假设一个网络调用示例,当调用multipleCallbacks()时,成功和失败的行为都可以定义在一个地方,这为将来的代码阅读器提供了更高的清晰度。

一般来说,根据我的经验,这种方法可以使整体更简洁,更简洁,更清晰。

祝你好运!

1
type FunctionName = (n: returnType) => any; 

class ClassName { 
    save(callback: FunctionName) : void { 
     callback(data); 
    } 
} 

这确实符合功能性编程范例。

相关问题