總目錄
從C#到TypeScript - 接口
為了更好的抽象出行為和屬性,TypeScript在ES6的基礎上增加了接口interface
。
C#也有interface,不過TypeScript的接口還不大一樣,C#里的接口一般是為類服務,讓類實現接口中定義的方法或屬性。
TypeScript在C#基礎上更進一步,由於JavaScript是門非常靈活的語言,TypeScript作為JavaScript的超集需要保持靈活性,所以接口在TypeScript里可以脫離具體的類,單獨作為類似契約的存在,接口里的屬性也並非一定需要實現。
類的接口
這和C#的差不多,描述了公共的成員;不過實現接口語法有點類似於Java,用的是implements。
interface Selectable {
isSelected: boolean;
}
class Control implements Selectable {
isSelected : boolean;
}
同C#一樣,接口可以多重繼承其他接口,用的是extends。
interface Editable {}
interface Deleteable {}
interface Changeable extends Editable, Deleteable {}
接口的屬性
接口的屬性可以定義為readonly
,這個和C#里只有get
沒有set
的屬性有點像,同樣,實現接口的類也不一定需要readonly
。
interface Selectable{
readonly isSelected: boolean;
}
class Control implements Selectable{
isSelected: boolean;
}
let s: Selectable = { isSelected : true };
s.isSelected = false; // 編譯出錯, readonly
let c: Control = { isSelected : true };
c.isSelected= false; // 沒問題
另外,接口還支持可選屬性,同C#的可空屬性一樣,用?
表示,實現接口的類可以不用實現可選屬性。
interface RequestConfig {
url: string;
body?: any;
}
class Request implements RequestConfig {
url: string;
}
接口不需要類的支持
在C#里面,接口如果沒有類來實現的話是沒有什么意義的,但在TypeScript里不一樣,接口可以單獨使用。
interface RequestConfig {
url: string;
body?: any;
}
let config: RequestConfig = {url: 'www.google.com'};
這種經常用在函數的參數上面,用來描述具體的參數,把具體的參數放到接口里,方便操作,也方便重構。
function Request(config: RequestConfig){
}
接口除了描述屬性外,還可以用來描述函數,不過一個接口只能描述一個函數,描述時定義好參數和返回值即可。
從實現上看有點類似於C#的delegate
。
interface CheckLogin {
(name: string, pwd: string): boolean;
}
let check: CheckLogin = function(name: string, pwd: string): boolean {
return false;
}
另外,接口還可以用來描述可索引類型,就有點類似C#的Dictionary
。
索引支持兩種:number
和string
。
//定義一個Dict,key是string,value也是string
interface Dict {
[key: string] : string;
}
let dict: Dict = { 'key1': 'value1', 'key2': 'value2'};
console.info(dict['key1']); // value1
console.info(dict['key']); // undefined
接口繼承類
這在C#中很不可思議,接口居然還可以反過來繼承類,不過對於JavaScript里來說,靈活方便很重要,所以TypeScript實現了這個功能來快速生成一個接口。
雖說在比較復雜的繼承關系時可能會有用,不過個人認為這個功能還是有點雞肋,因為復雜的繼承通常會引入一些問題如緊耦合,牽一發而動全身,再加上這個,可能更讓人摸不着頭腦,不如用組合來得好。
接口繼承類時會繼承類中所有的成員,不管是private
,protected
還是public
,只是不包括其實現。
不過繼承了一個類不公開成員的接口只能被該類或該類的子類實現。
class User{
name: string;
protected pwd: string = "123";
}
class Admin extends User{
constructor(n: string, p: string){
super();
this.name = n;
this.pwd = p;
}
}
interface UserConfig extends User{ //這里包含了name和private的pwd
}
let config: UserConfig = new Admin('brook', '123');
泛型
TypeScript是同C#一樣支持泛型的,而且在使用方面也差不多,在接口名后面加上<T>
即可。
interface Testable<T> {
field: T;
(arg: T): T;
}
也支持泛型約束,關鍵字是extends
。
interface Testable<T extends Object> {
field: T;
(arg: T): T;
}
TypeScript的接口對於C#程序員來說是有點奇怪了,不過用過之后還是發現非常符合JavaScript語言靈活的特性。