# W_TypeScript note
## TS 簡易基礎
- TypeScript 只會進行靜態檢查,如果發現有錯誤,編譯的時候就會報錯。
# 基礎
## 聯合型別
一般來說 ts 的變數宣告只能接受一個特定的值,但如果我給變數設定兩個可接收的型別,那就可以接收兩個型別,下方範例可以看到有兩個型別並且用|分割
```typescript=
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
```
## 抽象與介面
這兩個是 TS 才有的語法,可以想像是只 JS 的類,只是再把它拆分更加嚴謹
## 抽象 abstract
- 建立一個抽象類別,定義函式但沒有具體公用,通常 value 是 void
- void 代表著子類要自己實做方法,簡單來說就是空的,子類自己定義內容
- 當子類要繼承它,就嚴格規定要使用祖先的函式,並且只能繼承一個方法
- 不能直接 new 祖先類(父類),但子可以
- 可以使用共用邏輯,比如
- move() {
console.log(`${this.name} is moving.`);
}
```typescript=
abstract class Animal {
abstract makeSound(): void;
}
class Dog extends Animal {
makeSound() {
console.log("Woof!");
}
}
```
## 介面 interface
- 建立一個合約,如果子類要繼承它,需要將裡面的屬性與方法一併繼承
- interface 可以 extened interface,這樣子類可以一次繼承到兩個方法
- 子可以繼承多interface
```typescript=
//interface 可以 extened interface,這樣子類可以一次繼承到兩個方法
interface Animal {
name: string;
}
interface Dog extends Animal {
bark(): void;
}
const pet: Dog = {
name: "Barky",
bark() {
console.log("Woof!");
}
};
```
## 變數、引數須強制加上型別
```typescript=
//這是ts寫法
let number: number = 25;
//如果要讓變數有自由度可以加上 :any 或是為空
let number: any = 25;
let number;
//fnc 的變數需要強制加上型別,讓引數必須為此型別
function name(person:string){
console.log(`this name is ${person}`)
}
```
## 物件型別
在 Ts 裡面,是用 interfaces 來定義物件型別,下面例子展示作法
```typescript=
//設定強制規則,之後使用都要按造此規則,否則將會抱錯
interface Person {
name:string
age:number
}
//正常使用
let tom:Person{
name: "tom"
age:25
}
//不正常,少一項
let tom:Person{
name: "tom"
}
//不正常,多了一項 interface 沒有的東西
let tom:Person{
name: "tom"
age:25
gender:male
}
////////////////////////////
//可以看到 age 後方多了一個問號,這代表屬性非強制繼承
interface Person{
name:string
age?:name
}
// 正常,雖然少了一項,但不會抱錯,因為 ? 表示可選擇使用
let tom:Person{
name: "tom"
}
////////////////////////////
//在規則裡新增一項可選擇性增加的屬性
interface Person{
name:string
age?:name
//首先[]裡代表屬性名稱是字串,再來就是接收值可以是任意
[propName:sting]:any
}
// 正常,雖然少了一項,但不會抱錯,因為 ? 表示可選擇使用
let tom:Person{
name: "tom"
age:25
gender:male
}
////////////////////////////\
//唯讀,不能賦值
interdace Person{
readonly id: number
}
//這會錯誤
let tom:Person{
}
tom.id = 1
```
## 陣列型別
其實道理跟物件差不多
```typescript=
let sum:number[] = [1,2,3,4,5]
//不正常,不能有字串的出現ㄑ
let sum:number[] = [1,"2",3,4,5]
```
## 泛型
在 TypeScript 中,函式或變數都需要明確指定型別(如 string、number 等),這叫做強型別(strong typing)。當你希望程式更有彈性與重用性,可以根據「實際傳入的值」自動決定型別,就可以使用 泛型(Generic)。
- 泛型的語法是 `<T>`,它會在使用時根據實際傳入的值,自動推斷或手動指定型別,
- `<T>` 是介於 any(完全沒限制)與明確型別(如 string)之間的「彈性型別」。
- `<T>` 的T是標示符,T可以自己定義名稱,只要有<>就是泛型,一般來說有會有代表的意思
| 常用名稱 | 含義說明 |
|---|---|
| `T` | Type,最常見的泛型名稱 |
| `U`, `V` | 當有多個型別參數時常用第二、第三個名 |
| `K` | Key,常用於鍵的泛型 |
| `V` | Value,常用於值的泛型 |
| `E` | Element,用於集合元素 |
| `TData` | 更語意化的寫法,例如 TData, TResult |
### 泛型疑問
- 泛型是甚麼
- 所以依照範例 `log<string>('Hello')` 是指說檢查log()裡面的內容是否為字串,哪我是否可以寫成 console.log("hello"):string,還是規則就是要<>
- `<T>`是甚麼,依照範例,可以任意賦值近陣列中嗎
- 所以如果寫`<T>`就表示一樣也是要強制型別,但是依照傳入的值來定義,比如`log<string>('Hello')`,這就是我要定義這個log是字串,而引述也要強制寫成字串,是這個意思嗎,
- `<T>` 不像 :string :number 那樣的寫死,也不像 :any 的隨意,我這樣理解正確嗎
- 如果還不確定要傳入甚麼強制的值,就可以用`<T>`
- 你說彈性擴充,那跟 any 差異?