2013-02-01 99 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); 
    } 
} 

這確實符合功能性編程範例。

相關問題