owned this note
owned this note
Published
Linked with GitHub
# 初探TypeScript
## TypeScript 到底是什麼?
由 Microsoft 主打,擁有型別系統(Type System)與介面(Interface)設計的語言,
<!-- TypeScript 可以想成他是在原生 JS 上包裝上一層新的語法,因此如果在 TypeScript 裡面編譯原生 JS 也是可以動作的,只不過有可能發生錯誤的原因是:TypeScript 會幫你把原生 JS 裡潛藏的 Bug 或者是沒有補清的邏輯拋出警訊(Warning)的動作。 -->
### TypeScript 與 JavaScript 的相容性
TypeScript 是 ECMAScript 2015 (ECMAScript 6 或 ES6) 的 strict 超集。 這表示所有的 JavaScript 程式碼也是 TypeScript 程式碼,而 TypeScript 程式可順利地取用 JavaScript。
瀏覽器只能了解 JavaScript。 為了讓您的應用程式得以運作,使用 TypeScript 撰寫時,請編譯程式碼,並將其轉換為 JavaScript。

[圖片來源](https://ithelp.ithome.com.tw/articles/10215904)
### TypeScript 本身的優點
1. 加強「Type」部分的JavaScript
2. 開發完成後還是需要編譯成JavaScript
3. 適用於開發前後端
<hr/>
## 建立環境
新增
```bash=
npm install -g typescript
```
TS 初始化設置文件並會產生tsconfig.json 檔案
```bash=
tsc --init
```
預設的config檔案
```bash=
{
"compilerOptions": {
"target": "es2016", //指定編譯生成的JS版本
"module": "commonjs", //指定生成哪種模組
"strict": true, //採用嚴格模式
"esModuleInterop": true, //兼容模組導入的方式
}
}
```
新增我們config檔案設定,[其他詳細的config設定
](https://ithelp.ithome.com.tw/articles/10263733)
```bash=
"outDir": "./dist", //完成編譯後生成 js 文件的路徑
"rootDir": "./src", //代表 ts 文件的入口路徑
"strictNullChecks": true // 將 null 與 undefined 視為不同的型別
"strictPropertyInitialization":false //啟用所有嚴格類型檢查模式
```

[圖片來源](https://ithelp.ithome.com.tw/articles/10218577)
(在預設狀況下(strictNullCheck 為 false),值為 undefined 或 null會被推論為 any型別,因為這時候 undefined 和 null 可以是任何資料型別的值)
<hr/>
## 第一個 TypeScript 專案
沒有安裝過 TypeScript 的話,必須先安裝它的指令工具,記得用 -g
```bash=
npm install -g typescript
```
初始化專案,取得TypeScript 編譯器的設定檔
```
tsc --init
```

建立一個檔案`index.ts`
```typescript=
const message='Hi';
function say(something:string):void{
console.log(something);
}
say(message);
```
執行編譯
TypeScript 編譯器就會幫我們自動掃描所有 .ts 結尾的檔案並且產出 JS 檔案。
(在未提供其他參數的情況下執行,會編譯目前資料夾中所有的.ts檔案,額外延伸[ tsc 命令列介面文件](https://www.typescriptlang.org/docs/handbook/compiler-options.html))
```bash=
tsc
```


<hr/>
好用指令推推
每當TS檔案有改變時,自動編譯JS檔案
```bash=
tsc --watch
```
<hr/>
### 型別推論(Type Inference)
使用「類型提示」來識別變數或參數的資料類型。
→ 可透過靜態類型檢查,在開發初期就找出程式碼問題。
``` typescript=
let a =123;
// TS 編譯器便會自動推論出資料型別為number
```
結論:没有明確指定型別的情況下,由 TS 自動判斷型別
### 型別斷言(Type Assertion)
編譯器接受開發者手動寫下型別,並且不會再送出警告錯誤。
語法:
1. `<型別>值` (angle-bracket <>)寫法
``` typescript=
let code: any = 123;
let employeeCode = <number> code;
```
2. `值as 型別 `(as keyword)寫法
``` typescript=
let code: any = 123;
let employeeCode = code as number;
```
:::info
兩者寫法效果相同,但React專案使用JSX語法時只能用第二種。
:::
結論:手動指定資料型別,可以覆蓋掉 TS 自動推論的資料型別
### 型別註解(Type Annotation)
使用手動註解的方式,明確宣告資料型別,告訴編譯器必須符合註解的類型。
語法:在變數、參數或屬性後面加上冒號`:型別`
```typescript=
//變數的型別註解
const age: number = 32
//函式參數的型別註解
function display(name: string){
console.log(name);
}
//函式參數/回傳值的型別註解
function display(a: number,b: number): number{
return a + b
}
```
結論:明確指定資料型別。
### 型別註解 v.s 型別斷言
1. 大部分情況下會使用型別註解 ; 型別斷言使用情境較少。
2. 型別註解告訴編譯器這個資料必須永遠都是這個型別 ; 而型別斷言則主要用在覆蓋 TS 編譯器自動進行的型別推斷和型別相容性規則(Type Compatibility),告訴編譯器你知道這個值要符合斷言的型別,從而避免了上面範例中型別不兼容的錯誤產生。關於兼容性的討論在stackoverflow看到不錯的討論。
3. 型別註解大部分使用在初始化階段,像是宣告變數、函式參數或回傳值型別等 ; 而型別斷言可能用在接收外部參數,中間過程需要明確指定資料型別的時候
<hr/>
## 資料型態
基本型別(Basic Types)
| Type | 型別分類 | 筆記 |
| -------- | -------- | -------- |
| string | primitive | 定義字串型別。 |
| number | primitive | 定義數值型別。 |
| boolean | primitive | 定義布林值型別。 |
| null | primitive | 定義空值型別, 亦可賦值給所有型別(嚴謹模式則無法),something is currently unavailable(當你使用在宣告了變數,但又不想讓它是未定義的狀態)。 |
| undefined | primitive | 定義 undefined 型別,亦可賦值給所有型別(嚴謹模式則無法), something hasn't been initialized(變數沒有被宣告,或者是已經宣告了,但是沒有賦值) |
```typescript=
// -----------------基本類型-----------------
let name1:string = 'bob'
let name2:string = "bob"
// 支援 10 進制和 16 進制,也支援 ES6 的 2 進制和 8 進制的最新寫法
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// ES6 中的 2 進制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的 8 進制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
let boo:boolean=true;
let name: any;
name = undefined // OK
name = null // OK
let age: undefined;
age = undefined // OK
age = null // Error
age = 123 // Error
let spot: null;
spot = null // OK
spot = undefined // Error
spot = 123 // Error
```
:::info
JSON value 不支援 undefined
:::
TypeScript 才有的型別 : any、unknown、void、 never、 union types(聯合型別) 、intersection types(交集型別)、 literal types(字面值型別)、 tuple(元組)、 enums(列舉)。
| Type | 型別分類 | 筆記 |
| -------- | -------- | -------- |
| object | object | 定義物件型別。 |
| arrays | object | 可使用「型別 + 方括號」或陣列泛型來表示陣列。 |
| function | object |一個函式有輸入和輸出,可以針對參數(輸入)及返回值(輸出)進行型別規範。 |
```typescript=
// 陣列
let arr:string[]=['a','b'];
let arr:Array<string>=['a','b'];
let arr2:string[][]=[['aa','bb',1]]
let arr3:string[][]=[['aa','bb'],[1]]
let combine = [1, 'hi', 'hello', 2 ,'world'];
// 針對混合型態的陣列推論結果為 (string | number)[],TS會當作聯合型別(union)來處理
```
```typescript=
// ----------------- object -----------------
type Card={
name:string;
desc:string;
}
interface Card2{
name:string;
desc:string;
}
const obj :Card={
name:'bbb',
desc:"---"
};
```
```typescript=
// ----------------- object -----------------
type Card={
name:string;
desc:string;
}
interface Card2{
name:string;
desc:string;
}
interface Card2{
age?:number;
// 代表可以是number或undefined
}
const obj :Card2={
name:'bbb',
desc:"---"
};
```
```typescript=
//----------------- 泛型 -----------------
function p<T>(data:T){
console.log('data',data)
}
p<number>(9000);
p<string>('wewe');
p<boolean>(false);
```
```typescript=
//---------Function--------------
//函式宣告式
function add(x: number, y: number):number {
return x + y;
}
// 函式表達式(匿名函式)
let add = function(x: number, y: number) {
return x + y;
};
```
<!-- TypeScript 中的 => 和 ES6 中的 =>是不同的!
這裡的=>用來表示函式的型別定義,左邊是輸入型別,需要用括號刮起來,右邊則是輸出型別。但其實只在等式一邊有型別 -->
| Type | 型別分類 | 筆記 |
| -------- | -------- | -------- |
| any | TS | 表示允許賦值為任意型別。 |
| unknown | TS | unknown 和 any 一樣可以接受任何型別賦值,但 any 可以賦值給任何型別,unknown 只能賦值給 any 和自己。 |
| void | TS |表示沒有任何返回值的函式。 |
| never | TS |來表示不應該存在的狀態的型別,一般用於錯誤處理函式。 |
| union types | TS |聯合型別(union type) 使用|表示其定義的值可以為多種型別。 |
| intersection types | TS |交集型別(intersection type) 使用 & 表示其定義的值都必須符合多種型別。 |
|literal types | TS |某些特殊的"值"可以當作"型別"來使用。 |
| tuple | TS |tuple 就是合併了不同型別的物件。 |
| enum | TS |列舉(enum)型別可以用來管理多個同系列的常數,作為狀態判斷使用。 |
```typescript=
type A =number | string;
let z :A; //變數Z屬於A類型,可接受number與string
z='wewewewew';
z=12121212;
z=true
//物陣列的元素沒有你要的型別,可以用 union 聯合型別進行型別註記
//不限定數量只要元素符合型別
let foo: (string| number)[] = ['hello', 'ya', 'yeah'];
//或
let foo: Array<string | number> = ['hello', 'ya', 'yeah'];
```
``` typescript=
// 元組,元素個數必須固定,各個元素格式也必須完全吻合
let tuple:[number,String,boolean]=[1,'a',true];
let tuple2:[String,String]=['a','a'];
// -----------------Enum 枚舉-----------------
// 以座位感測來舉例
enum SeatStatus{
ERROR= -1,
USING= 0,
AVAILABLE= 1,
IDLE_TOO_LONG= 2,
}
const staus=SeatStatus.ERROR;
```
```typescript=
// -----------------交集-----------------
type Info1 ={
name: string,
age: number
}
type Info2 = {
isGirl : boolean,
nickname: string
}
type IntersecInfo = Info1 & Info2
let person5 : IntersecInfo ={
name : 'Una',
age: 18,
isGirl : true,
nickname: 'Nana'
}
```
指定物件的類型
:::info
type vs interface:interface是可以擴充的但type不行
:::
物件導向
```typescript=
//----------------- class -----------------
// private
// public
// protected
class Live{
public roomName:string;
private id :string;
protected name:string;
constructor(roomName1:string,id1:string,name1:string){
console.log('直播中...')
this.roomName=roomName1;
this.id=id1;
this.name=name1;
}
}
const live=new Live('1賀','011111','12121');
console.log(live);
```
參考資料:https://docs.microsoft.com/zh-tw/learn/modules/typescript-get-started/2-typescript-overview
https://ithelp.ithome.com.tw/articles/10217384
https://ithelp.ithome.com.tw/articles/10220016
###### tags: `TS`