Easyfun Easy fun Easy to play

Typescript

Typescript起始

使用typescript要先了解什麼是強型別(Strongly Typed)&弱型別(Weakly Typed)

1 + 1;

這結果是1+1=2。

1 + “1”;

這結果就不一定了,如果是在Javascript裡的話就是直接轉型字串相加變成字串”11”。

但是在Ruby和Rust裡會直接報錯,因為他們是屬於強型別。這就是強型別和弱型別的差異,有沒有自動轉型(Coerce)。

那Typescript是強型別還是弱型別呢??

普遍人都覺得他是強性別比較嚴謹,其實他是屬於弱型別語言,還是跟Javascript一樣,擁有自動轉型。因為他本身就是Javascript的超集合概念,任何Javascript可經由Typescript編譯,根據Javascript帶有型別轉換功能,Tyopescript也要可被編譯。

所以Typescript算是一門漸進式型別系統(Gradual Typing)的弱型別(Weekly Typed)。

Typescript最大差異

Typescript比Javascript多出的功能就是型別系統(Type System),這個型別系統具備兩種功能,型別的註記及推論。

Typescript的型別推論(Inference)的功能,就是不需藉由明顯的文字註記性的提示,而是根據變數被指派到的值之型別,又或是表達式運算結果之值的結果進行型別方面推論。Typescript也會提醒開發者記得要去處理這方面的情境。

Typescript幫你檢測之結果,除了是正常以為的數字型別外,還另外提醒有可能為undefined的邊界情境。

型別推論與註記使用時機

1.Typescript的程式碼必須評估各種狀況選擇加上型別註記或者讓程式自行推論。

2.通常積極做註記是為了限縮型別的各種可能性,使程式碼可以減少要處理的例外狀況個數、增加模糊變數或使用上的可讀性以及讓Typescript編譯器靜態偵測程式,確保型別不會有衝突產生。

3.如果某段或某行程式碼本身可讀性夠或者是從命名上直覺判斷出型別的機率夠高的話,通常Typescript型別系統的推論機制就夠。

型別註記-註記與斷言的差異

分的細一點還可分成兩種:註記(Annotation)與斷言(Assertion)。

型別註記語法

基本的註記語法,就是帶有冒號相關的語法。

let randomNumber: number = Math.random(); const myName: string = ‘Maxwell’; const subscribed: boolean = true;

如果遇到函數的話,參數(Argument)部分除了可以有類似的註記方式標明輸入的參數型別外,在函式參數宣告結尾也可以註記該函式輸出之型別。

以名為isPositive的函式,示範輸入為數字型別,輸出則是布林型別的函式是如何在宣告的同時註記:

function isPositive(inputL number): boolean {
  return input > 0;
}

// isPositive為檢測輸入值是否為正數的函式
// @param input: number為輸入的數字
// @output boolean 為輸出的結果,如果是正數,則輸出為true

在Javascript裡宣告的方法很多,這是將函式作為值指派到變數裡。

換成指派型寫法:

const isPositive: (input: number) => boolean = function(input) {
  return input > 0;
}

函式型別的註記部分不是:

(input: number): boolean

而是改用箭頭(Arrow)的方式表示:

(input: number) => boolean

在宣告變數isPositive時,早就用過一次冒號了,後續為了不要混淆,只得用箭頭的方式表示該函式型別。這個型別表示的方式與ES6箭頭函式(Arrow Function)沒有關係,箭頭函式是可以被呼叫的函式,而箭頭方式表示的函式型別是一種註記方式,可被呼叫函式跟註記是不相干的東西。

也可把變數指派的函式改成ES6箭頭函式的格式也可以,就只是指派運算子(Assignment Operator),左方是函式的型別註記表示法,右方則是普通函式的宣告內容。

const isPositive: (input: number) => boolean = input => input > 0;

改成推論被指派的函式型別:

const isPositive = function(input: number): boolean { return input > 0; }

換成ES6箭頭函式也是一樣:

const isPositive = (inputL number): boolean => input > 0;

🏒 註記的基礎語法Syntax of Type Annotation

1.變數的註記-假設宣告某一變數foo,並想將其註記為某型別T時,則基本的註記語法格式如:

<let const> foo: T =

2.函式的宣告與註記-假設某一函式bar,並想將其參數p1到pn分別註記為T1到Tn時,輸出的型別為T_Output,則基本的註記語法格式如:

function bar(p1: T1, p2: T2, …, pn: Tn): T_output { /* 函式的宣告內容 / }

3.變數為函式型別的註記-假設宣告某一變數bar,並想將其註記為某函式型別為T時,且T之參數p1到p_n分別註記為T_1到T_n時,輸出的型別為T_Output,則註記於指派運算子左方的註記方式為:

const bar: (p1: T1, p2: T2, …, p_n: T_n) => T_Output =

; 註記於指派運算子右方,並且合併函式的宣告時,註記方式如: const bar: (p1: T1, p2: T2, ..., p_n: T_n) => T_Output { /* 函式的宣告內容 / } 換成ES6箭頭函式的格式則是: const bar: (p1: T1, p2: T2, ..., p_n: T_n) => T_Output => { /* 箭頭函式的宣告內容 / } ### 型別斷言語法 斷言(Assertion)是有使用關鍵字或者(...)的格式就是斷言的用法。通常會用到斷言的情境是-程式沒辦法推論(Inference)某表達式(Expression)的確切運算結果之型別,我們才會選擇使出斷言來處理。 沒辦法推論就像是使用第三方的資源,像是使用Json API獲得的內容之型別格式、讀取檔案轉成JSON物件結果、使用套件提供的功能、呼叫會回傳未知結果的函式等。 假設有個函式名為returnsUnknown,程式本身可能不知道它會回傳什麼樣的型別,但你可能是參考過某外在來源、套件提供的文件等第三方資源,後來得知他絕對會回傳某特定型別-以數字為例,使用斷言的語法會長這樣: const aNumber = returnsUnknown() as number; 或者是 const aNumber = (returnsUnknown()); 斷言的部分,沒有人斷言在變數的名稱宣告部分,以下為錯誤: const aNumber as number = returnsUnknown(); // 這是錯誤的 函式的宣告表達式也可以被斷言(函式作為表達式也會被當成值),以isPositive函式如下: const isPositive = (input => input > 0) as (input: number) => boolean; 或者是 const isPositive = <(input: number) => boolean>(input => input > 0); 基礎註記手法: const isPositive: (input: number) => boolean = input => input > 0; 或者是 const isPositive = (input: number): boolean => input > 0; 這四種寫法效果差不多,但是註記跟斷言的語法意義上就差很多。 ### 敘述式(Statement)與表達式(Expression)的定義與差別 1.敘述式代表的概念是程式運行的流程。像在JS裡的判斷敘述式(if...else...)以及迴圈敘述式(for或者是while迴圈)。 2.表達式代表的則是程式碼運算的流程,並且會將運算結果回傳(Return)其中,兩者的差異是:「敘述式不會回傳值、表達式會回傳」。
/* 運算表達式Arithmetic Expression /

1 + 2 * 3; // 回傳結果:7

/* 邏輯表達式Logical Expression /

true && (something === null || myAge < 18) // 回傳結果:true或false

/* 函式(或方法)的呼叫Function/Method Inocation Expression /

Math.pow(2, 10); // 回傳結果: 1024

/* 三元運算子Ternary Operator /

myAge < 18 ? 'Youngster' : 'Adult'; // 回傳結果: 'Youngster', myAge < 18

}
/* 判斷敘述式Conditional Statement /

if (/* Expression1 /) {
  /* 若Expression1為true則執行此/
} else if (/* Expression2 /) {
  /* 若Expression2為true則執行此 /
} else {
  /* 若Expression1與Expression2皆不為true則執行此 /
}

/* 迴圈敘述式Looping Statement /
while (/* Expression /) {
  /* 若Expression為true則重複執行直到Expression為false時跳脫 /
}