從開始學習前端之後,大多的學習資源都是來自線上課程、youtube 影片為主,鮮少透過閱讀書籍來學習相關知識,但自從進入公司之後,因為公司內有些程式書籍能夠借閱,先是從 JavaScript 大全開始,一開始閱讀起來真的滿痛苦,不知道該如何消化內容,直接順著讀過去又怕忘記,但目前還是順順的讀到了第8章~後來,找到的方式就是在筆記軟體上做些註記,工作上遇到相關的再回過頭看一次,加入筆記。
而在此次,發現 TypeScript 即便已經看過介紹型別、基本使用基礎的影片後,仍然覺得不太足夠,所以就開始翻閱書籍 「讓 TypeScript 成為你全端開發的 ACE」,文中介紹滿多之前沒有注意到觀念、也有帶到不少 JavaScript 的觀念來呼應。所以本篇,多是來自於書中資訊,透過整理呈現。
註記 Annotation V.S. 斷言 Assertion
- 型別註記:指在告訴 TS 編譯器:「任何被註記到的變數、函式的參數等,都必須遵照被註記過後的變數型別」。
- 所以編譯器會隨時隨地的監測該變數有沒有出現型別衝突的可能—關鍵字為遵照。
- 而,斷言型別則是無視 TS 編譯器分析整個程式碼的型別推論過程,果斷的告訴 TS 編譯器:「被斷言過後的表達式之運算結果就是某某型別」—關鍵意象是「覆蓋」該表達式的型別推論結果。
註記與斷言
1 2
| let randomNumber:number = Math.random(); const subscribed:boolean = true;
|
- 如果遇到函式,參數(Argument)部分除了可以有類似註記方式標明輸入的參數型別外,在參數宣告結尾也可以註記該函式輸出之型別。
1 2 3
| function isPositive(input: number):boolean{ return input > 0 }
|
- 但JS裡,宣告函式的方法有很多種,其中一個是將函式最為值指派到變數。
1 2 3
| const isPositive:(input:number) => boolean = function(input){ return input > 0 }
|
- 以上,也能把變數指派的函式,改成ES6箭頭函式
- 指派運算子(Assignment Operator ,就是指程式裡的等號)左方是函式的型別註記表示法,右方則是普通函式宣告
1
| const isPositive:(input:number) => boolean = input => input >0;
|
1 2 3
| const isPositive = function (input:number):boolean{ return input>0 }
|
1 2
| const isPositive = (input:number):boolean => input>0
|
型別斷言語法
- 斷言(Assertion)的語法很簡單,看到有使用關鍵字 as 或者
<T>(...)
的格式就是斷言的用法。
- 通常會使用斷言的情境,程式沒辦法推論某表達式的確切運算結果之型別,我們才會用選擇使出斷言來處理這種情境。
- 程式沒辦法推論?
- 使用第三方的資源(Third-party resources),如使用外來JSON API 獲得的內容之型別格式、讀取檔案轉成 JSON 物件的結果、使用套件提供的功能、呼叫會回傳未知結果的函式。
1
| const aNumber = returnsUnknow() as number;
|
或是這樣:
1
| const aNumber = <number>(returnsUnkonw());
|
- 請注意:斷言的語法部分,沒有人斷言在變數的名稱宣告部分—也就是是說,如果你這樣寫是錯的:
1
| const aNumber as number = returnsUnknow();
|
- 概念有點像,決斷地告訴程式,某表達式的運算結果之型別。
- 變數本身不是被運算,而是被指派某個東西,而斷言應該是斷在被指派的值或表達式的運算結果上。
複雜一點
- 函式宣告表達式有可以被斷言(畢竟函式作為表達式也會被當成值)
1
| const isPositive =(input => input > 0) as (input: number) => boolean
|
或者是:
1
| const isPositive = <(input: number) => boolean>(input => input >0);
|
1
| const isPositive :(input: number) => boolean = input => input >0;
|
或者是
1
| const isPositive =(input: number):boolean => input >0;
|
說下,敘述式與表達式的定義與差別
- 敘述式:程式運行的流程,例如:JS 裡的判斷敘述式(if…else)以及迴圈敘述式(for 或者是 while 迴圈)。
- 表達式代表的則是程式碼運算的流程,並且會將運算結果回傳。其中兩者最關鍵差異為:敘述式不會回傳值,表達式則會。
1 2 3 4 5 6 7 8 9 10
| 1+2*3 ;
true && (something === null || myAge < 18)
Math.pow(2,10)
myAge < 18 ? 'Youngster' : 'Adult';
|
而敘述式:
1 2 3 4 5 6 7 8 9 10 11 12 13
| if(){ }else if(){ } else{ }
while (){ }
|
- 按照上面敘述式的定義 — 由於敘述式是在敘述運行流程,而不會回傳值,所以你才不會在 JavaScript 裡面看到這樣的寫法:
1 2 3 4 5 6
| const status = if(Age <18 ){ return 'Young' }else{ return 'Adult' }
|
- 注意:敘述式不一定是多行式(或區塊式)地呈現的最佳案例:變數宣告的指派敘述式(Variable Declaration Assignment Statement)
- 請問上面指派式會回傳什麼結果 =>數字 123 或 udefined。正解為 udefined
- 所以可以歸納出,javaScript 的變數宣告的指派式屬於敘述式,非表達式。
表達式什麼時候會以非單行的程式碼,也就是區塊的方式?
1 2 3 4
| const status = (funcrion(myAge){ if (myAge <18){ return 'Young'} return 'Adult' })(16)
|
- 當可以分清楚表達式與敘述式差別後,回歸型別斷言
- 斷言的基礎語法
- 斷言的語法只能用在表達式上,因為表達式具備回傳值,敘述式則沒有
- 因此,可以「斷言該表達式所運算結果之代表型別」
寫法如下:
1 2 3
| <expression> as T assertion
<T assertion >(<expression>)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| (foo+bar*baz) as number;
(isPositive(num) && idEven(num)) as boolean;
Math.pow(2, 10) as number
(myAge <18 ? 'Young' : 'Adult') as string;
(funcrion(myAge){ if (myAge <18){ return 'Young'} return 'Adult' })(16) as number
somefunction(foo as number , bar as string) as boolean
|
換種寫法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <number>(foo+bar*baz);
<boolean> (isPositive(num) && idEven(num)) ;
<number> Math.pow(2, 10) ;
<string>(myAge <18 ? 'Young' : 'Adult') ;
<number>( funcrion(myAge){ if (myAge <18){ return 'Young'} return 'Adult' })(16) );
<boolean>somefunction(foo as number , bar as string)
|
以上針對註記 Annotation V.S. 斷言 Assertion 做個簡單整理~