经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » TypeScript » 查看文章
项目中使用TypeScript的TodoList实例详解
来源:jb51  时间:2023/1/6 8:52:27  对本文有异议

为什么用todolist

现代的框架教程目前再也不是写个hello world那么简单了,而是需要有一定基础能力能够做到数据绑定、遍历、条件判断等各种逻辑,而能完成这一系列内容的,todolist就是个很好的实现,比如react的教程、solijs教程都是以todolist为例

当然,你如果想看各种框架实现todolist的话,你可以访问TodoMVC 这里面展示了各种框…

todolist的ts化

但是对于ts教程来说,只有官方的一些实例,并没有一个很好的项目上的教程,也就是有关实战的部分,很多同学在学习了ts之后,只会一些基础的js类型的设置,放在项目中就不清楚了,所以我们就出了这个教程

当然在开始之前,我们要了解这个教程不依赖任何的前端库,比如react,vue等,同时也为了节省时间,我们仅仅是放出一些关键的ts代码,不需要将整个应用都展示出来,同样能够让你知道ts的使用

数据到视图

一个tudolist对应的数据是怎么样的?就拿刚才的视图来看的话,它应该是一个对象数组,数据应该是这样的

  1. [
  2. {
  3. id: 1,
  4. text: '待办事项1',
  5. done: false
  6. },
  7. {
  8. id: 2,
  9. text: '待办事项2',
  10. done: false
  11. },
  12. {
  13. id: 3,
  14. text: '待办事项3',
  15. done: false
  16. }
  17. ]

其中id是每一个代办事项的唯一标识,text是事项名称,done表示是否完成

当我们点击完成的时候,实际上就是每一项的done发生了变化,数据发生变化之后驱动我们的视图做出对应的改变

实现handleTodoItem

对应的上述的点击事件,我们实现一下它的伪代码,当其点击的时候,需要处理对应的数据,先使用js实现

  1. function handleTodoItem(todo){
  2. // 点击的时候todo中的done的布尔值取反
  3. return {
  4. ...todo,
  5. done: !todo.done
  6. }
  7. }

然后我们使用ts进行优化

  1. type Todo = {
  2. id: number;
  3. text: string;
  4. done: boolean;
  5. }
  6. // 如果某个变量是todo类型,可以这样
  7. const todoItem: Todo = {
  8. id: 1,
  9. text: '待办事项1',
  10. done: false
  11. }

这样ts类型就是正常的,如果相应的todoItem不匹配,则编译就会发生错误,可以让错误提前感知,并且如果项目中有配置的ts相关,vscode中就会给出对应的错误信息

对应到handleTodoItem这个方法中,应该怎么写呢?

  1. function handleTodoItem(todo: Todo): Todo {
  2. // 逻辑实现
  3. }

readonly

对于handleTodoItem这个函数来说,函数应该是无副作用的,所以传进去的todo对象,不应该发生变化,而是返回一个新的对象

比如这种方法,虽然能够实现同样的内容,但是它是有副作用的,改变了传入的参数,是不可取的

  1. function handleTodoItem(todo: Todo):Todo {
  2. // 点击的时候todo中的done的布尔值取反
  3. todo.done = !todo.done
  4. return todo
  5. }

但是这种的ts并不会报错,怎么办?那就需要借助我们的ts进行类型校验,你可以这样

  1. type Todo = {
  2. readonly id: number;
  3. readonly text: string;
  4. readonly done: boolean;
  5. }

当你尝试修改修改的话,就会发生ts错误,不允许修改,因为Todo类型是只读的,当然你也可以这样设置对象中所有的属性为只读

  1. type Todo = Readonly<{
  2. id: number;
  3. text: string;
  4. done: boolean;
  5. }>

在ts中,这种Readonly的关键词还有很多,比如Required,Partial等,如有需要,大家可自行搜索

分类

对于已经完成的list,我们需要将其进行分类筛选,比如我们要筛选出所有已经完成的项目,那么表现就是一个数组,并且done为true

  1. [
  2. {
  3. id: 1,
  4. text: '待办事项1',
  5. done: true
  6. },
  7. {
  8. id: 2,
  9. text: '待办事项2',
  10. done: true
  11. }
  12. ]

如何表示一个数组类内容呢?Todo[]这种方式就能表示上述数据,同样的,函数的参数是不允许修改的,避免副作用,所以可以这样

  1. function completeTodoList(
  2. todos: readonly Todo[]
  3. ): Todo[] {
  4. // ...
  5. }

当然,由于Todo的type中的done为boolean,但是在completeTodoList中done的值为true,所以我们需要重新定义一个类型

  1. type CompletedTodo = Readonly<{
  2. id: number;
  3. text: string;
  4. done: true;
  5. }>

所以上述的方法就会变成

  1. function completeTodoList(
  2. todos: readonly Todo[]
  3. ): CompletedTodo[] {
  4. // ...
  5. }

交叉类型

对于上面的Todo和CompletedTodo类型,其中这两个类型的id和text都是重复的,我们可以删除重复的逻辑,使用交叉类型

举个例子

  1. type A = {a: number}
  2. type B = {b: string}
  3. type AandB = A & B
  4. // 结果为
  5. // {
  6. // a: number
  7. // b: string
  8. // }

当两个类型key相同时,第二个key会覆盖掉第一个的内容

  1. type A = {key: number}
  2. type B = {key: string}
  3. type AandB = A & B
  4. // 结果为
  5. // {
  6. // key: string
  7. // }

那针对Todo和CompletedTodo类型,我们想从Todo通过交叉类型得到CompletedTodo,该怎么做呢?

  1. type CompletedTodo = Todo & {
  2. readonly done: true
  3. }

是不是很简洁,并且去除了一些重复代码

新增功能

如果在Todo的基础上,我们新增了一个功能,对应的todo的优先级,使用priority这个字段表示

并且一共有三种优先级

!!!

!!

你可以priority: 2这样设置,展示为【!!】当然你也可以自定义,比如

  1. {
  2. priority: {
  3. custom: '紧急'
  4. }
  5. }

则展示为【紧急】,所以这时候数据变成了

  1. [
  2. {
  3. id: 1,
  4. text: '待办事项1',
  5. done: false,
  6. priority: 1
  7. },
  8. {
  9. id: 2,
  10. text: '待办事项2',
  11. done: false,
  12. priority: 2
  13. },
  14. {
  15. id: 3,
  16. text: '待办事项3',
  17. done: false,
  18. priority: {
  19. custom: '紧急'
  20. }
  21. },
  22. {
  23. id: 4,
  24. text: '待办事项4',
  25. done: false
  26. },
  27. ]

我们已经有了Todo类型,如何新增一个key呢?

联合类型

上面我们之后交叉类型通过 & 连接,那联合类型则是通过 | 连接,同样的举个例子

  1. type Foo = number | string;

这表示Foo类型可以是一个数字,也可以是一个string类型,所以我们的priority类型可以这样设置

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

这个时候priority就是我们想要的内容了,所以todo的类型可以变一下

  1. type Todo = Readonly<{
  2. id: number;
  3. text: string;
  4. done: boolean;
  5. priority: Priority;
  6. }>

可选属性

上面的priority这个属性目前是必填的,但是这个属性我们可以不写,也就是todo可以没有优先级,针对这种情况,我们可以使用可选属性

  1. type Todo = Readonly<{
  2. id: number;
  3. text: string;
  4. done: boolean;
  5. priority?: Priority;
  6. }>

在对应的地方添加一个?即可

数据转视图

那对应的priority的数据有了,如何把1,2,3这种的转成!!!的形式呢?

可以自定义一个函数,也就是priorityToString

  1. priorityToString(1)
  2. // !
  3. priorityToString(2)
  4. // !!
  5. priorityToString(3)
  6. // !!!
  7. priorityToString({ custom: '紧急' })
  8. // 紧急

情况比较少,可能你会这样写

  1. function priorityToString(priority: Priority): string {
  2. if(priority === 1){
  3. return '!'
  4. }else if(priority === 2){
  5. return '!!'
  6. }else if(priority === 3){
  7. return '!!!'
  8. }else{
  9. return priority.custom
  10. }
  11. }

联合类型我们通过if条件进行判断的时候,它会自动确认每个if条件下的参数类型,这也是联合类型的强大之处

总结

基本上我们项目中用到的一些知识点这里都概括了,通过一个简单的项目,将ts的一些基本类型给大家做了一个简要的说明

参考:ts.chibicode.com/todo/

以上就是项目中使用TypeScript的TodoList实例详解的详细内容,更多关于TypeScript TodoList使用的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号