---
# typescript 筆記
## 前言
- 一個基於 JavaScript 的超集合(SuperSet)
- 提供型別系統(Type System),能夠在開發時期宣告型別
- 支援 ECMAScript,可將 TS 檔編譯成 JS 檔給瀏覽器解讀
## 型別系統 Type System
由於javescript是弱型別語言,typescript的出現就是要解決這個問題
typescript就是javascript的延伸其支援ECMAScript規範所以可以支援js代碼
**舉例typescript與javascript差異 :**
原生javascript :

typescript :

以上的範例可以看出typescript是如何註記型別,typescript的原始型別有以下幾種 :
### Boolean
使用 boolean 定義布林值型別 :
``` typescript=
let isToggle:boolean = false
```
注意:使用建構函式 Boolean 建立的物件不是布林值:
``` typescript=
let isToggle:boolean = new Boolean(1)
```
直接呼叫Boolean返回的是一個boolean型別 :
``` typescript=
let isToggle:boolean = new Boolean(1)
```
在typescipt中,boolean是基本型別,而Boolean是建構函式
### String
使用 String 定義字串型別 :
``` typescript=
let myName:string = "Danny"
```
typescript 支援樣本字串:
``` typescript=
let age:number = 10
let myName:string = 'Danny'
let sentense = `Hellow my Name is ${myName} my age is ${age}`
```
使用樣本字串創建type:
``` typescript=
type Direction = 'row'|'column'
type Position = 'center'|'right'|'left'
type PositionVarants = `${Position} - ${Position}`
```
型別推論結果是 :

註 : typescript會透過樣本字串結合新型別
### Number
使用 Number 定義字串型別 :
``` typescript=
let decLiteral: number = 6;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
```
### 空值
在typescrupt可以透過void,表示沒有返回任何值的函式:
``` typescript=
function sayHellow():void{
console.log('Hellow world')
}
```
### Null 和 Undefined
使用 **null** 和 **undefined** 來定義這兩個原始資料型別:
``` typescript=
let u: undefined = undefined;
let n: null = null;
```
undefined 和 null 是所有型別的子型別。也就是說 undefined 型別的變數,可以賦值給 number 型別的變數:
``` typescript=
let num:number = undefined
```
### 陣列
使用 []定義原始型別集合:
``` typescript=
let animals:string[]=['lion','pig']
let peopleNo:number[]=[10,5]
```
### 任意值
賦予變數任何型別:
``` typescript=
let addressNO:any=281
```
### 列舉型別 enum
以下為例 :
``` typescript=
enum Color {Red,Green,Blue}//output : 0,1,2
let c:Color =Color.Green //1
```
編譯結果:
``` typescript =
var Color;
(function (Color) {
Color[Color["Red"] = 0] = "Red";
Color[Color["Green"] = 1] = "Green";
Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
```
可以看到enum的概念是一個object,值=鍵,鍵=值
## 型別推論(Type Inference)
>TypeScript會依據型別規則推導出一個資料型別
以下方程式碼為例:
```typescript=
let myLuckyNumber = 12
```
等同於上方:
```typescript=
let myLuckyNumber:number = 12
```
如經過TS型別推論後的變數,再指定其他值會報錯:
```typescript=
let myLuckyNumber:number = 12
myLuckyNumber = '7'
// index.ts(2,1): error TS2322: Type 'string' is not assignable to type 'number'.
```
### e.g.自動註記

```
message變數就被推論為string
```
## 型別斷言 Type Assertion
> 當最後需要改變變數型別時,為了避免出現警告錯誤,這個機制就是『型別斷言』
型別斷言有兩種寫法
- 第一種 :`<型別值>`
``` typescript=
let code: any = 'Hello';
let helloCode = <string> code;
```
- 第二種 :`值as型別`
``` typescript=
let code: any = 'Hello';
let helloCode =code as string;
```
## Utility Types
### Required<Type>
簡單舉個Utility Types例子 :
```typescript=
interface Props {
a?: number;
b?: string;
}
const obj2:Required<Props>={
a:5
}
//obj2會報錯因為b已經不是可選項的屬性
```
Required<Type>是typescript原生的type可以讓型別中的可選項變成reuired
[更多範例 ...](https://www.typescriptlang.org/docs/handbook/utility-types.html)
## interface vs type
## 相同點
### type
```typescript=
type User={
name:string
age:number
}
let user:User={
name:'Danny',
age:20
}
```
以上我們定義一個型別User他有name、age兩個,透過user指定User型別告訴蓋變數有name、age以及其對應的型別
### interface
```typescript=
interface User={
name:string
age:number
}
let user:User={
name:'Danny',
age:20
}
```
註 :與type寫法類似但對typescript來說是不同的解釋,type是個型別用引而interface是產生一個新型別,interface算是一個介面的延伸如class一樣介面可以extend屬性但type不能,如以下例子 :
## 不同點
### overwrite
```typescript=
interface info {
personName:string
}
interface info {
addressNo:number
}
```
介面info可以透過複寫的方式延伸型別
### extend
```typescript=
interface Mailable {
send(email: string): boolean
queue(email: string): boolean
}
interface FutureMailable extends Mailable {
later(email: string, after: number): boolean
}
```
註 :以上的FutureMailable就是一個繼承的概念,FutureMailable擁有Mailable的屬性同時增加later函式的方法
### 一個class可以繼承多個屬性
```typescript=
interface Mailable {
send(email: string): boolean
queue(email: string): boolean
}
interface FutureMailable {
later(email: string, after: number): boolean
}
class Mail implements FutureMailable,Mailable {
later(email: string, after: number): boolean {
console.log(`Send email to ${email} in ${after} ms.`);
return true;
}
send(email: string): boolean {
console.log(`Sent email to ${email} after ${after} ms. `);
return true;
}
queue(email: string): boolean {
console.log(`Queue an email to ${email}.`);
return true;
}
}
```
以上敘FutureMailable為例,在class中使用interface去繼承型別使用的關鍵字是implements,如需使用多個介面只要在後面新增就好。
## Mixins
<T>為typescript optional type的方法,只需要再函數括號前新增就好
```typescript=
function base<T>() {
class Base {
static prop: T;
}
return Base;
}
function derivedg<T>(){
class Derived extends base<T>() {
static anotherProps:T
}
return Derived
}
class Spec extends derivedg<string>(){}
Spec.anotherProps//string
Spec.prop//string
```
上述是一個class的mixins設定,derived函數是繼承Base函數的方法,class Spec可以繼承derived回敷函數的調用結果讓Spec繼承class Base、Derived,也因為optional type的關係Spec.anotherProps的型別結果是String
## typescript 編譯設定
全局安裝typescript
```
npm install typescript -g
```
mac 安裝全域套件記得加sudo
```
sudo npm install typescript -g
```
初始化ts專案
```
tsc --init
```
專案中會跑出tsconfig.json這支檔案

註 :tsconfig.json為ts編譯的設定檔案
例如outDir就是要檔案編譯後要放的資料夾

typescript很貼心在tsconfig.json中每一個option都有解釋說明用法非常直觀。
### 小結
儘管javascript自由度很高,但在型別使用上卻有缺陷,時常搞不清楚api呼叫後的結果是什麼,typescript的出現就是要補足這個問題,typescript的主要概念有兩個,其一Type Inference,自動推倒變數結果防止變數型別錯亂,其二就是Type Assertion,當一個變數可能會有多個以上的型別時,就可以夠過斷言決定變數想要的結果為何,也算是typescript提供的自由度。12