前言 這篇文章主要來紀錄 TypeScript 的學習紀錄
 
使用的教材有
TypeScript Tutorial  
本文  
 
什麼是 TypeScript TypeScript 是 JavaScript 的延伸,也就是說,TypeScript 是建立在 JavaScript 之上的
因此我們可以透過 TypeScript 編譯器  來讓 TypeScript 程式碼轉換為 JavaScript。
 
那我們也可以將一個沒有語法錯誤的 JS 程式  視為 TS 程式 ,因此在這兩種語言之間進行轉換,所需要的成本是相對比較低的。
透過引進 型別  到 JS,能夠使開發過程更加嚴謹,進一步減少 Bugs。
Basic Type Type Annotation 透過 Type Annotations  的方式來表明變數的型態
1 let <variable>: <type>: <value> 
 
E.g.
如果指定錯誤的值,會發生 compiler error
1 let  name: number = 'one' ; 
 
指定一個 sayHello function,並回傳 strin
1 2 3 4 5 6 7 8 9 10 let  sayHello: (name: string ) =>  string;const  hello = function (name: string )  {    return  `Hi ${name} `  } const  hello = function (name: string )  {    return  `Hi ${name} `  } 
 
Type Inference 與 Type Annotation 相反, Type Inference 是不表明型態 的方式。
E.g.
 
Type Inference vs. Type Annotation 在大多數的實務上都會使用 Type Inference,會使用 Type Annotation 的時機
先宣告變數而不定義 
希望變數的型態不透過 TypeScript 推論 
當函式回傳 any 
 
Best common type algorithm 假如今天有一個變數如下,TypeScript 會主動給予該變數一個最適合的變數型態
1 2 3 4 5 let  items = [1 , 2 , 3 , null ]; let  items = [0 , 1 , null , 'Hi' ] let  array = [new  Date (), new  RegExp ('\d+' )]; 
 
Contextual typing Contextual 代表變數會隨著前後文來決定自己的型態
1 2 3 4 5 6 7 8 9 document .addEventListener('click' , function  (event )  {    console .log(event.button);  }); document .addEventListener('scroll' , function  (event )  {    console .log(event.button);  }); 
 
Object Type object 代表的是所有非原型(primitive)型別的值。
TypeScript 的原型型別
number 
bigint 
string 
boolean 
null 
undefined 
sybmol 
 
 
定義 object 變數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let  employee: object;employee = {     firstName : 'Percy' ,     lastName : 'Chen' ,     age : 22 ,     jobTitle : 'Web Developer'  }; console .log(employee)
 
Object 與 object 容易搞混的有是 Object,後者所代表的是所有 objects 所能使用的功能,也就是說在 typescript 中幾乎所有的值都有 toString() & valueOf 這些功能可以使用。 
empty type {} {} 代表一個沒有任何屬性存在內的 object,如果想要存取 object 的值會發生 compiler error
1 2 let  vacant: {};vacant.name = 'Percy' ;  
 
array array 是一個有序的資料,定義的方法如下
 
1 2 3 4 5 6 7 8 let  skills: string[];skills = ['a' , 'b' ] skills.push(123 )  
 
properties & methods array 有許多 屬性  及 方法  可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let  series = [0 , 1 , 2 , 3 , 4 ]console .log(series.length) series.map(v  =>  v^2 )  let  sum = 0 ;console .log(series.forEach(function (value ) {sum += value}))let  tmp = series.reduce(function (pre_value, cur_value, ) {return  pre_value+cur_value}, 5 ) 
 
mixed type 1 2 3 4 5 6 let  scores = ['Programming' , 5 , 'Software Design' , 4 ]; let  scores2 : (string  | number )[];scores2 = ['a' , 'b' , 1 ] 
 
Tuple 比起 Array,Tuple 多了更多條件
1 2 3 4 5 let  skills: [number , string ]skills = ['box' , 5 ]   skills = [5 , 'box' ]   
 
Optional tuple elements 從 TypeScript 3.0 開始,便可以透過 ? 來表示一個 tuple 的內容是非必填的。
1 2 3 let  bgColor, headerColor : [number , number , number , number ?];bgColor = [0 , 255 , 255 , 0.5 ]; headerColor = [0 , 255 , 255 ];   
 
Enum Enum 是一組常數數值,可以用來定義一連串有關聯性的變數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 enum  Month {    Jan,     Feb,     Mar,     Apr,     May,     Jun,     Jul,     Aug,     Sep,     Oct,     Nov,     Dec }; enum  Month {    A = 5 ,     B,     C,     D,     E } 
 
Any type 如果在宣告的時候沒有給予型態,那 typescript 會透過 type inference 的特性給予這些變數any 的型態。
可以透過修改 tsconfig.json 的 noImplictAny 數值來停用自動賦予 any 的這個特性
 
any vs. object 使用 any 的情境下,在變數沒有該方法可以呼叫時,也不會出現錯誤訊息;相反的,使用 object,可以提早知道錯誤的資訊。
1 2 3 4 5 6 7 8 9 let  result: any ;result = 10.123 ;  console .log(result.toFixed()); result.willExist(); let  result: object ;result = 10.123 ;  console .log(result.toFixed()); result.willExist();  
 
Void 與 any 剛好相反, void 表示的是沒有任何型態,通常會用來表示不回傳任何值的狀況
1 2 3 function  lo (message: string  ): void  {    console .log(message) } 
 
never never 通常被使用來表示回傳的格式中會 觸發錯誤 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function  raiseError (message: string  ): never   {    throw  new  Error (message) } function  reject ( )  {    return  raiseError('Rejected' ) } let  loop = () =>  {    while  (true ){         console .log("Hello!" );     } } 
 
union union 用來描述一個變數可能會有多種型態的狀況。
 
Type Alias type alias 賦予現有的型態新的名字
1 2 3 4 5 6 7 8 9 10 11 12 13 type  chars = string ;let  name: chars;  type  alphanumeric = number  | string ;let  value: alphanumeric;value = 'Percy' ;  value = 100 ;  value = false ;  
 
string literal types 透過 宣告不同的字串  來達成 自定義的型態 。
1 2 3 4 5 6 7 8 9 10 11 12 13 let  tax: 'tax' ;tax = 'tax' ; tax = 'tax1' ;  let  petsound: 'Meow'  | 'woof' petsound = 'Meow' ; petsound = 'woof' ; petsound = 'woooof' ;   let  anotherpetsound: petsound
 
Control Flow Statements Functions Rest Parameter rest parameter 意味著函式的參數可以接受零到多個參數,此外還有以下規定:
一個函式只能有一個  rest parameter 
只能出現在參數的最後一個位子 
是一個 array 格式 
 
1 2 3 4 5 6 7 8 9 function  fn (...names: string [] ): void  {    names.forEach((name )=>  console .log(name)) } fn("Percy" , "Chen" ) 
 
Classes 在 ES6 以前,在 JS 中並沒有類別 class 的概念,在 ES6 之後變具備了建立 class 的語法糖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Person   {    firstName : string ;     lastName: string ;     age: number ;     constructor (firstName: string , lastName: string , age: number  )  {         this .firstName = firstName;         this .lastName = lastName;         this .age = age;     }     getHelloMessage ( )  {         return  `Welcome ${this .lastName}  ${this .firstName} !`      } } let  person = new  Person('Percy' , 'Chen' , 27 );console .log(person.getHelloMessage());
 
Access Modifiers 存取修飾符 Access Modifiers 是用來修改類別的 屬性 & 方法 的能見度 ,在 TypeScript 中提供了三種
private 
protected 
public(預設) 
 
private private 將能見度限制在類別內,意味著類別以外的人是不能夠存取的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Person   {    firstName : string ;     lastName: string ;     age: number ;     constructor (firstName: string , lastName: string , age: number  )  {         this .firstName = firstName;         this .lastName = lastName;         this .age = age;     }     getHelloMessage ( )  {         return  `Welcome ${this .lastName}  ${this .firstName} !`      } } let  person = new  Person('Percy' , 'Chen' , 27 );console .log(person.fiirstname); 
 
public public 的屬性可以在任何地方被存取,在沒有使用修飾符的狀況下,預設都是使用 public。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Person   {    (public ) firstName: string ;     (public ) lastName: string ;     (public ) age: number ;     constructor (firstName: string , lastName: string , age: number  )  {         this .firstName = firstName;         this .lastName = lastName;         this .age = age;     }     getHelloMessage ( )  {         return  `Welcome ${this .lastName}  ${this .firstName} !`      } } let  person = new  Person('Percy' , 'Chen' , 27 );console .log(person.getHelloMessage());
 
protected protected 是允許 自己類別  以及 子類別存取  的屬性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Person {     (procted) firstName: string;     (public) lastName: string;     (public) age: number;     constructor(firstName: string, lastName: string, age: number) {         this.firstName = firstName;         this.lastName = lastName;         this.age = age;     }     getHelloMessage() {         return `Welcome ${this.lastName} ${this.firstName}!`     } } let person = new Person('Percy', 'Chen', 27); console.log(person.getHelloMessage()); 
 
readonly 透過 readonly 讓類別屬性不可變(immutable),與 const 的差異在於,前者用在類別屬性,後者用在一般變數。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Person2   {    readonly  birthDate: Date ;     constructor (birthDate: Date  )  {         this .birthDate = birthDate;     } } let  person2 = new  Person2(new  Date (2010 , 10 , 25 ));person2.birthDate = new  Date (2002 , 1 , 2 );  
 
Static properties static 在整個類別及其實例中共用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  StaticBox  {    static  initCount: number  = 0      constructor (         private  length: number ,         private  width: number ,         private  color: string ,      ) {        StaticBox.initCount+=1       }     public  static  getCounter(): number  {         return  StaticBox.initCount;     } } let  box1: StaticBox = new  StaticBox(3 , 4 , 'Blue' )console .log(StaticBox.getCounter())let  box2: StaticBox = new  StaticBox(1 , 2 , 'Red' )console .log(StaticBox.getCounter())
 
Interface 將不同的變數透過 interface 的方式包裝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function  getFullName (person: {     firstName: string ;     lastName: string ; } )  {    return  `${person.firstName}  ${person.lastName} `  } let  person4 = {    firstName : 'John' ,     lastName : 'Doe'  }; console .log(getFullName(person4));
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 interface  Person3 {    firstName : string ;     lastName: string ; } function  getFullName2 (person: Person3 )  {    return  `${person.firstName}  ${person.lastName} ` ; } let  me = {    firstName : 'Percy' ,     lastName : 'Chen'  } console .log(getFullName2(me))
 
function types 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 interface  IsTeeanger {    (age: number ): string  } let  checkIsTeen: IsTeeanger;checkIsTeen = function  (age: number  )  {     return  age < 18  ? "YES"  : "NO"   } checkIsTeen = function (anotherage: number  )  {     return  anotherage < 18  ? "YES"  : "NO"   } console .log(checkIsTeen(45 ))
 
class types 1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface  Json {    toVolume(): number  } class  Box  implements  Json   {    constructor (private  length: number , private  width: number  ) {}     toVolume(): number  {         return  this .length * this .width     } } let  box = new  Box(5 , 12 );console .log(box.toVolume());
 
Advanced Types Intersection Type intersection type 代表的是透過多個型態組合成一個新型態。
1 2 type  typeAB = typeA & typeB;
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 interface  Person {    name : string ;     sex: string ; } interface  Info {    address : string ;     identity: string ; } type  resident1 = Person & Infotype  resident2 = Person | Info let  man: resident1 = {    name : "Percy" ,     sex : "Man" ,     address : "Taipei" ,     identity : "haha"  } let  man2: resident2 = {    name : "Percy" ,     address : "Taipei" ,     identity : "haha"   } 
 
型態的順序不影響 type intersection
 
Modules 透過模組化 modules,可以將 A 檔案的內容傳遞給 B 檔案做使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function  foo  (number : number  ): boolean  {    if  (number  % 2  == 0 ){         return  true      } else  {         return  false      }          } export  {foo}import  * as  mod from  "./my_module" ; console .log(mod.foo(5 ))