首頁 > 軟體

專案中使用TypeScript的TodoList範例詳解

2023-01-06 14:00:25

為什麼用todolist

現代的框架教學目前再也不是寫個hello world那麼簡單了,而是需要有一定基礎能力能夠做到資料繫結、遍歷、條件判斷等各種邏輯,而能完成這一系列內容的,todolist就是個很好的實現,比如react的教學、solijs教學都是以todolist為例

當然,你如果想看各種框架實現todolist的話,你可以存取TodoMVC 這裡面展示了各種框…

todolist的ts化

但是對於ts教學來說,只有官方的一些範例,並沒有一個很好的專案上的教學,也就是有關實戰的部分,很多同學在學習了ts之後,只會一些基礎的js型別的設定,放在專案中就不清楚了,所以我們就出了這個教學

當然在開始之前,我們要了解這個教學不依賴任何的前端庫,比如react,vue等,同時也為了節省時間,我們僅僅是放出一些關鍵的ts程式碼,不需要將整個應用都展示出來,同樣能夠讓你知道ts的使用

資料到檢視

一個tudolist對應的資料是怎麼樣的?就拿剛才的檢視來看的話,它應該是一個物件陣列,資料應該是這樣的

[
  {
    id: 1,
    text: '待辦事項1',
    done: false
  },
  {
    id: 2,
    text: '待辦事項2',
    done: false
  },
  {
    id: 3,
    text: '待辦事項3',
    done: false
  }
]

其中id是每一個代辦事項的唯一標識,text是事項名稱,done表示是否完成

當我們點選完成的時候,實際上就是每一項的done發生了變化,資料發生變化之後驅動我們的檢視做出對應的改變

實現handleTodoItem

對應的上述的點選事件,我們實現一下它的虛擬碼,當其點選的時候,需要處理對應的資料,先使用js實現

function handleTodoItem(todo){
  // 點選的時候todo中的done的布林值取反
  return {
    ...todo,
    done: !todo.done
  }
}

然後我們使用ts進行優化

type Todo = {
  id: number;
  text: string;
  done: boolean;
}
// 如果某個變數是todo型別,可以這樣
const todoItem: Todo = {
  id: 1,
  text: '待辦事項1',
  done: false
}

這樣ts型別就是正常的,如果相應的todoItem不匹配,則編譯就會發生錯誤,可以讓錯誤提前感知,並且如果專案中有設定的ts相關,vscode中就會給出對應的錯誤資訊

對應到handleTodoItem這個方法中,應該怎麼寫呢?

function handleTodoItem(todo: Todo): Todo {
  // 邏輯實現
}

readonly

對於handleTodoItem這個函數來說,函數應該是無副作用的,所以傳進去的todo物件,不應該發生變化,而是返回一個新的物件

比如這種方法,雖然能夠實現同樣的內容,但是它是有副作用的,改變了傳入的引數,是不可取的

function handleTodoItem(todo: Todo):Todo {
  // 點選的時候todo中的done的布林值取反
  todo.done = !todo.done
  return todo
}

但是這種的ts並不會報錯,怎麼辦?那就需要藉助我們的ts進行型別校驗,你可以這樣

type Todo = {
  readonly id: number;
  readonly text: string;
  readonly done: boolean;
}

當你嘗試修改修改的話,就會發生ts錯誤,不允許修改,因為Todo型別是唯讀的,當然你也可以這樣設定物件中所有的屬性為唯讀

type Todo = Readonly<{
  id: number;
  text: string;
  done: boolean;
}>

在ts中,這種Readonly的關鍵詞還有很多,比如Required,Partial等,如有需要,大家可自行搜尋

分類

對於已經完成的list,我們需要將其進行分類篩選,比如我們要篩選出所有已經完成的專案,那麼表現就是一個陣列,並且done為true

[
  {
    id: 1,
    text: '待辦事項1',
    done: true
  },
  {
    id: 2,
    text: '待辦事項2',
    done: true
  }
]

如何表示一個陣列類內容呢?Todo[]這種方式就能表示上述資料,同樣的,函數的引數是不允許修改的,避免副作用,所以可以這樣

function completeTodoList(
  todos: readonly Todo[]
): Todo[] {
  // ...
}

當然,由於Todo的type中的done為boolean,但是在completeTodoList中done的值為true,所以我們需要重新定義一個型別

type CompletedTodo = Readonly<{
  id: number;
  text: string;
  done: true;
}>

所以上述的方法就會變成

function completeTodoList(
  todos: readonly Todo[]
): CompletedTodo[] {
  // ...
}

交叉型別

對於上面的Todo和CompletedTodo型別,其中這兩個型別的id和text都是重複的,我們可以刪除重複的邏輯,使用交叉型別

舉個例子

type A = {a: number}
type B = {b: string}
type AandB = A & B
// 結果為
// {
//   a: number
//   b: string
// }

當兩個型別key相同時,第二個key會覆蓋掉第一個的內容

type A = {key: number}
type B = {key: string}
type AandB = A & B
// 結果為
// {
//   key: string
// }

那針對Todo和CompletedTodo型別,我們想從Todo通過交叉型別得到CompletedTodo,該怎麼做呢?

type CompletedTodo = Todo & {
  readonly done: true
}

是不是很簡潔,並且去除了一些重複程式碼

新增功能

如果在Todo的基礎上,我們新增了一個功能,對應的todo的優先順序,使用priority這個欄位表示

並且一共有三種優先順序

!!!

!!

你可以priority: 2這樣設定,展示為【!!】當然你也可以自定義,比如

{
  priority: {
    custom: '緊急'
  }
}

則展示為【緊急】,所以這時候資料變成了

[
  {
    id: 1,
    text: '待辦事項1',
    done: false,
    priority: 1
  },
  {
    id: 2,
    text: '待辦事項2',
    done: false,
    priority: 2
  },
  {
    id: 3,
    text: '待辦事項3',
    done: false,
    priority: {
      custom: '緊急'
    }
  },
  {
    id: 4,
    text: '待辦事項4',
    done: false
  },
]

我們已經有了Todo型別,如何新增一個key呢?

聯合型別

上面我們之後交叉型別通過 & 連線,那聯合型別則是通過 | 連線,同樣的舉個例子

type Foo = number | string;

這表示Foo型別可以是一個數位,也可以是一個string型別,所以我們的priority型別可以這樣設定

type Priority = 1 | 2 | 3 | { custom: string };

這個時候priority就是我們想要的內容了,所以todo的型別可以變一下

type Todo = Readonly<{
  id: number;
  text: string;
  done: boolean;
  priority: Priority;
}>

可選屬性

上面的priority這個屬性目前是必填的,但是這個屬性我們可以不寫,也就是todo可以沒有優先順序,針對這種情況,我們可以使用可選屬性

type Todo = Readonly<{
  id: number;
  text: string;
  done: boolean;
  priority?: Priority;
}>

在對應的地方新增一個?即可

資料轉檢視

那對應的priority的資料有了,如何把1,2,3這種的轉成!!!的形式呢?

可以自定義一個函數,也就是priorityToString

priorityToString(1)
// !
priorityToString(2)
// !!
priorityToString(3)
// !!!
priorityToString({ custom: '緊急' })
// 緊急

情況比較少,可能你會這樣寫

function priorityToString(priority: Priority): string {
  if(priority === 1){
    return '!'
  }else if(priority === 2){
    return '!!'
  }else if(priority === 3){
    return '!!!'
  }else{
    return priority.custom
  }
}

聯合型別我們通過if條件進行判斷的時候,它會自動確認每個if條件下的引數型別,這也是聯合型別的強大之處

總結

基本上我們專案中用到的一些知識點這裡都概括了,通過一個簡單的專案,將ts的一些基本型別給大家做了一個簡要的說明

參考:ts.chibicode.com/todo/

以上就是專案中使用TypeScript的TodoList範例詳解的詳細內容,更多關於TypeScript TodoList使用的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com