Skip to main content

TypeScript

  • Enum 類似利用 JavaScript 定義常數的概念

    enum Animal {
    DOG = "dog",
    CAT = "cat",
    }

    const a = Animal.DOG
  • 泛型:從呼叫 function 或 class 時來規範型態

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

    print<number>123;

    // class 用法
    class Print<T> {
    data: T;
    constructor(d: T) {
    this.data = d;
    }
    }

    const p = new Print<number>(123);
    • 也可用於 function 回傳結果的定義(定義回傳結果陣列中的內容是 string 類型)
    // 也可以為泛型定定義預設的型別,例如 function createArray<T = string>(length: number, value: T): Array<T> {...},如果在呼叫這個 function 的參數無法從參數自動推導出型別的話,這個預設型別就會起作用
    function createArray<T>(length: number, value: T): Array<T> {
    let result: T[] = [];

    for (let i = 0; i < length; i++) {
    result[i] = value;
    }
    return result;
    }

    createArray<string>(5, "x"); // 這邊的 <string> 也可以不寫,讓型別推論自動推導出來
    • 約束泛型:只允許讓傳入的參數有 length 這個屬性
    interface Lengthwise {
    length: number;
    }

    function loggingIdentity<T extends Lengthwise>(arg: T): T {
    return arg;
    }
      type Person = {
    name: string;
    id: number;
    };

    function getValue<T, U extends keyof T>(obj: T, key: U) {
    return obj[key];
    };

    getValue<Person, "id">(obj, "id");
    // 限制只能從 Person 取得 id 的 key
  • type 跟 interface 差別差在 interface 可以擴充,type 不行

    interface Card {
    id: string;
    name: string;
    }

    interface Card {
    desc: string;
    }
    • interface 之間也可以是繼承的關係
    interface Alarm {
    alert();
    }

    interface LightableAlarm extends Alarm {
    lightOn();
    lightOff();
    }
  • union

let a: string;
a = "123";
  • type
type Data = string;

let a: Data = "123";
  • class 的 implements
interface CarPops {
name: string;
}
class Car implements CarPops {
name: string;
}
  • utility:typescript 提供的一些方法,可參考官網

    • Record<Keys, Type>:除了用於定義 object 內容
    interface CatInfo {
    age: number;
    breed: string;
    }

    type CatName = "miffy" | "boris" | "mordred";

    // 第一個參數 CatName 是 key name,第二個參數是物件內容
    const cats: Record<CatName, CatInfo> = {
    miffy: { age: 10, breed: "Persian" },
    boris: { age: 5, breed: "Maine Coon" },
    mordred: { age: 16, breed: "British Shorthair" },
    };

    // 也可以用於以下,讓物件內容都是 string 或 boolean
    const object1: Record<string, boolean> = {
    name: true,
    id: "123",
    };
  • class:分為 public、private、protected,但只侷限在 typescript 會提示錯誤,但實際 JavaScript 還是可以執行的

class Live {
public roomName: string; // 預設 public,不限制各地方存取
private id: string; // 不能在子類別存取,宣告的地方也不能去更改他
protected name: string; // 允許在子類別中存取
constructor(roomName1: string, id1: string, name1: string) {
this.roomName = roomName1;
this.id = id1;
this.name = name1;
}
}

class CarLive extends Live {
constructor(roomName1: string, id1: string, name1: string) {
super(roomName1, id1, name1)
};

start() {
console.log(super.name)
}
}

  • ! 驚嘆號:表示這個值不是 null 或是 undefined

  • 在 React 中定義 TypeScript 可參考這篇 React Typescript CheatSheet

  • keyof:取出物件的 key 當作 type(後面接的值要是 typescript 的型別)

    • 如果後面要接 JavaScript 的型別,可以用 keyof typeof 來取代
type Person = {
firstName: string;
lastName: string;
}

type PersonKey = keyof Person; // 用以取代需要寫 "firstName" | "lastName" 以及避免之後 Person 新增 key
const personKey: PersonKey = "lastName"
enum MANUFACTURE {
APPLE = 'apple',
SAMSUNG = 'samsung',
GOOGLE = 'google',
SONY = 'sony',
}

type ManufactureKeys = keyof typeof MANUFACTURE; // 'APPLE' | 'SAMSUNG' | 'GOOGLE' | 'SONY'
type ManufactureValues = `${MANUFACTURE}`; // 'apple' | 'samsung' | 'google' | 'sony'

const object = {
name: "cindy",
id: 1,
}

type Test = typeof object; // { name: string; id: number; }
type Test2 = keyof typeof object; // "name" | "id"
  • as const:將物件轉成已讀屬性
const tabItem = [
{
name: "推薦",
key: "recommend",
},
{
name: "運動",
key: "sport"
},
{
name: "食物",
key: "food"
},
] as const;

// 游標移上去 const 就會顯示以下的 type
type const = readonly[{
readonly name: "推薦";
readonly key: "recommend";
},
{
readonly name: "運動";
readonly key: "sport";
},
{
readonly name: "食物";
readonly key: "food";
}]
  • readonly:將物件轉成唯讀屬性,一但被宣告後就不能再被更改
interface Person {
readonly id: number;
name: string;
age: number;
}

const person: Person = {
id: 1,
name: "cindy",
age: 30,
}

// 之後就沒辦法使用 person.id 來去更改 id
  • typeof:將變數變成型別
const obj = {
name: "cindy",
id: 1,
}

type Person = typeof obj
// type Person 會等於以下
type Person = {
name: string;
id: number;
}

// 如果需要使用到陣列中的物件的 value 可以寫成以下
const tabItem = [
{
name: "推薦",
key: "recommend",
},
{
name: "運動",
key: "sport"
},
{
name: "食物",
key: "food"
},
] as const;

type Key = typeof tabItem[number]["key"]
// Key 就會是只能使用 recommend、sport、food
  • Mapped Type:就不用多寫另一個對應的 type
type SupportedEvent = {
click: string;
change: string;
keyup: string;
keydown: string;
};

type HandledEvent = {
[K in keyof SupportedEvent]: () => void; // key 會包含 SupportedEvent 的 key,例如有 click、change、keyup、keydown
};
  • &:交集
type Animal = {
name: string;
age: number;
5: string;
};

type AnimalKeys = string & keyof Animal; // 只能是 string 且 Animal 的 key,所以會是 name、age

  • 修改 key 值
type SupportedEvent = {
click: string;
change: string;
keyup: string;
keydown: string;
5: number;
};

type MappedValuesToFunction<T> = {
[K in keyof T]: () => void;
};
type HandledEvent = MappedValuesToFunction<SupportedEvent>;

type HandledEventKeys = keyof HandledEvent & string; // "click" | "change" | "keyup" | "keydown"

type ToEventHandler<T> = {
[K in keyof T as `handle${Capitalize<string & K>}`]: T[K];
};
// 上面的 key 就會是 handleClick | handleChange | handleKeyup | handleKeydown

type EventHandler = ToEventHandler<HandledEvent>;
  • 泛型參數的預設值:可以讓使用者不用一定要傳入泛型參數,使用方式跟 JavaScript 的 object 預設值很像,也是用 = 來做
type Animal<T extends object, K extends keyof T = keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
// 如果沒有寫 = keyof T,就必須要傳入 K,不然會報錯

參考資料