Typescript Note - 安裝 / 型別 / 用法

Typescript Note - 安裝 / 型別 / 用法

Typescript 編譯安裝指令

  1. 全域安裝Typescriptnpm install -g typescript
  2. 專案資料夾 初始化 tsc --init 生成 tsconfig.json 配置檔
  3. Typescript compiler tsc hello.ts tsc 檔案名稱
  4. live watch tsc --watch
  5. 查看Typescript版本 tsc -v

tsconfig.json 配置檔

若要 compile 整個 src 資料夾
可更改配置輸入位置
"rootDir": "./src",
輸出位置
"outDir": "./dist",
指令 tsc 即可編譯整個資料夾底下的所有ts到dist資料夾

建議開啟source map 可以在除錯時更快找到原始ts檔
"sourceMap": true,

若有舊檔案js 需要import
可開啟
"allowJs": true,

null undefined原始設定在number情況會被接受
"strictNullChecks": true

Typescript = JS + type system

原始型別 Primitive Types 物件型別 Object Types
Number Object
String Array
Boolean Function
Undefined Date
Null RegExp
Symbol Error …(其他內建)
BigInt

原始型別 容易出錯的地方

1
2
3
4
5
6
7
8
let num1 = 999
let num2: number; //若無值也沒有宣告型別,則會被判斷為any,這種情況建議避免。

let un1 = undefined //型別會被推斷為any
let un2: undefined //型別指定為undefined

let n1 = null //型別會被推斷為any
let n2: null //型別指定為null

Union 聯合型別

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const arr: (string | boolean)[] = []
arr.push(false)
arr.push('')

let name: string | number;

function displayPrice(price: number | [number, number]){
if(typeof price === "number"){
console.log(`價格:${price}`)
}else{
console.log(`價格範圍:${price[0]}~${price[1]}`)
}
}

displayPrice(49.99);
displayPrice([33,55])

Array

1
2
3
4
5
6
7
const arr1 = [1, 2, 3]  // number[]
const arr2 = [1, 2, '3'] // (number | string)[]

const arr3: string[] = []
const arr4: Array<string> = [] // 泛型與 string[]相同

const arr5: string[][] = [['1', '2'], ['3', '4']]

Tuple 元組

1
2
const tu1: [number, string, boolean] = [123, 'apple', false]
const tu2: [number, number][] = [[11, 22], [33, 44]]

Object 物件

1
2
3
4
let obj: { name: string, age?: number | undefined } // age?為選填
obj = {
name: 'Jay',
}

any / unknown

unknown : 可以用較安全的any來理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

const status = false
function getName() {
let name: unknown //這邊使用unknown 會在接下來的result做防護
if (status) {
name = 'Tom'
} else {
name = null
}
return name
}

const result = getName()
if (typeof result === 'string') {
result.split('')
}

Type Assertion 斷言 as

應用於原本不確定的回傳型別檔案,再賦予該檔案的型別

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
async function getData() {
const res = await fetch('https://jsonplaceholder.typicode.com/todos/1')
const data = await res.json() as { userId: number, id: number, title: string, completed: boolean }
console.log(data)
}

getData()

//DOM
const txt = document.querySelector(".taskName") as HTMLInputElement
console.log(txt.value)


// return 陣列 (避免union情況的發生)

// 寫法1 getArr自動推斷成return (string | number)[] 用as const 讓 id, age, userName對應到正確的型別
function getArr() {
return [0, 30, 'Kim'] as const
}
const [id, age, userName] = getArr()

// 寫法2 as直接定義型別
function getArr() {
return [0, 1, 'bruce'] as [number, number, string]
}

強制斷言

強制去轉型 先轉成unknown或是any 再轉成結果型別

1
2
let code1 = 999
let code2 = code1 as unknown as string

never 類型

1
2
3
4
5
6
7
8
9
10

let code: string | number
code = 'abc'
code = 123

// never 永遠不可能發生的類型,當寫出code是字串類型時,ts會報錯,因為code已經賦予成數字

if (typeof code === 'string') {
code.split() // Property 'split' does not exist on type 'never'
}

type 自定義類型

1
2
3
4
5
6
7
8
type Name = string | boolean | number
let name1: Name
let name2: Name
let name3: Name

type OBJ = { name: string, age: number }
let obj1: OBJ
let obj2: OBJ

interface 介面

1
2
3
4
5
6
7
8
9
interface UserCard {
name: string
age: number | null
}

const usercard: UserCard = {
name: '',
age: null
}

type vs interface

兩者除了寫法有點不太一樣外,interface擁有合併多個的功能,type則沒有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type Animal = {
name: string
}
type Cat = Animal
type Dog = Animal & {
age: number
}

let dog: Dog = {
name: 'dog',
age: 99
}

let cat: Cat = {
name: 'cat',
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface Animal {
name: string
}

interface Cat extends Animal {}


interface Dog extends Animal {
age: number
}

let dog: Dog = {
name: 'dog',
age: 99
}

let cat: Cat = {
name: 'cat',
}

更詳細的差異圖

更詳細介紹文章

interface 合併

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//interface可以重複宣告並合併

interface Animal {
name: string
}

interface Animal {
age: number
}

let dog: Animal = {}

//type無法重複宣告 無法兩者合併

type Animal = {
name: string
}

type Animal = {
age: number
}

let dog: Animal = {}

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

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

//枚舉成員從0開始排列與下方賦值寫法相同

enum Days {
Sun = 0,
Mon = 1,
Tue = 2,
Wed = 3,
Thu = 4,
Fri = 5,
Sat = 6
};

//也可以自定義賦值,但未定義賦值的成員會接著上一個+1遞增
有可能會有重複情況 Sun = 4 Thu = 4 導致使用上錯誤,要特別注意
enum Days {
Sun = 4,
Mon = 1,
Tue = 2,
Wed = 3,
Thu,
Fri,
Sat
};
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
enum TaskStatus {
Todo,
InProgress,
Done
}

// 空任務陣列

let tasks:{name:string,status:TaskStatus}[] = [];

// 新增陣列
function createTask(name: string){
tasks.push({
name: name,
status: TaskStatus.Todo
})
}

// 新增任務到任務列表
createTask("學習TS");
createTask("去超市購物");

//顯示任務

console.log(tasks);

function

1
2
3
4
5
6
7
8
9
10
11
12
13
//陳述式 Declaration
function checkNum(num: number): boolean {
return num > 10;
}

//表達式 Expression
let checkNum = function(num: number): boolean{
return num > 10;
}

let addNum: (a: number, b: number)=> number = function(a, b) {
return a+b;
}
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
53
54
55
56
57
58
59
60
61
62
// :後面 為回傳值的型別 指定為number 若沒寫則為ts自行推定為string
function get(a: number, b: string, c: boolean): number {
return Number(a + b);
}
get(99, '', true);

// ?為可選參數 ts會避免錯誤 而要求增加判斷
function setUser(name: string, age?: string) {
if (typeof age === 'string') {
return age.split('')
}
}

// type
type Info = {
name: string,
age: number
}

function createUserInfo(info: Info) {
console.log(info.name) //當使用info時會自動提示info內的屬性名稱
return info
}

// 回傳值 never
function getUserData(): never {
throw new Error('...')
}

// 沒有return 回傳值 void
function hello() {
console.log()
}

function printMessage(message: string): void{
alert("message");
}

// 構建函數的寫法 new
type CardObj = {
name: string
}

type CardCreator = {
new(name: string): CardObj
}

function createCard (cardCreator: CardCreator) {
return new cardCreator('abc')
}

// 簡易function泛型 <>
// 使用時才定義傳入參數的型別

function print<T>(data: T) {
console.log(data);
}

print<string>('abc')
print<number>(123)
print<boolean>(true)

overload function 過載

某些情況會需要傳入參數為不同型別,可以使用聯合型別union來做,但回傳值無法精確的定義回傳的型別為何,則可用過載的方式來定義傳入與回傳的型別

reverse 字串反轉 / 數字反轉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 聯合型別 union 
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}

// 過載 overload
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}

function …rest

有多個參數傳入的情況,數量不確定時

1
2
3
4
function calculate(...nums: number[]) {
console.log(nums);
}
calculate(1, 2, 3, 4, 5, 99, 3213)

使用斷言as

1
2
3
4
5
6
7
8
function calculate(a: number, b: number, c: number) {
console.log(a);
console.log(b);
console.log(c);
}

const nums = [1, 2, 3] as const
calculate(...nums)

Typescript Note - 安裝 / 型別 / 用法

https://kaiyuncheng.github.io/2024/01/02/Typescript_01/

Author

KaiYun Cheng

Posted on

2024-01-02

Updated on

2024-04-13

Licensed under

Comments

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×