React+TS+useReducer手撕一个todoList

发布于:2024-08-22 ⋅ 阅读:(23) ⋅ 点赞:(0)

1.首先需要具备TS的基础

附上链接:TS学习

这里也一并附上TS 官方文档地址:TS官方地址 

2.项目学习视频,B站其他博主的视频

这里附上链接:React+TS+useReducer手手撕一个todoList 

3.项目地址,可以直接clone到本地运行

todoList项目

注意:项目有点bug,点击复选框的时候有问题,欢迎指出问题并修正,谢谢!! 

这里再附上我学习TS 的笔记:

### 一.TS基础概念
#### 1.什么是TS
a.对比原理
* 是JS的一个超集,在原有基础上,增加了
可选静态类型
基于类的面向对象编程

1.编写项目 - 更利于架构管理
2.自主检测 - 编译期间检测
3.类型检测 - 支持了动态和静态类型检测 => 本质存在类型检测
4.运行流程上 - 依赖编译
5.复杂特性 - 模块化 泛型 接口

#### 2.TS基础类型和写法
* boolean underfined null string number array 
``` ts
let arr = ['a', 'b'];

// ts
let arr: string[] = ['a', 'b'];
```
* tuple - 元祖
```ts
let tupleType = [string, boolean]
tupleType = ['a', true]

```
* enum - 枚举

``` ts
// 数字类枚举 - 默认从0开始, 依次递增
enum Score {
    BAD,
    NG,
    GOOD,
    PREFECT
}
let score: Score = Score.BAD;

// 字符串类型 
enum Score {
    BAD = 'BAD',
    NG = 'NG',
    GOOD = 'GOOD',
    PREFECT = 'PREFECT'
}

// 反向映射
enum Score {
    BAD,
    NG,
    GOOD,
    PREFECT
}
let scoreName = Score[0]; // 'BAD'
let scoreValue = Score['BAD'] // 0

// 异构 - 字符串 + 数字
enum Score {
    A,
    B,
    C = 'C',
    D = 'D',
    E = 6,
    F
}

// 面试题:手写实现一个异构枚举?
let Enum ;
(function(Enum){
   Enum['A'] = 0;
   Enum['B'] = 1;
   Enum['C'] = 'C';
   Enum['D'] = 'D';
   Enum['E'] = 6;
   Enum['F'] = 7;

   Enum[0] = 'A';
   Enum[1] = 'B';
   Enum[6] = 'E';
   Enum[7] = 'F';

})(Enum || (Enum = {}))
```
* any unknown void
``` ts
    // any - 绕过所有检查 => 类型检查和编译筛查全部失效
    let anyValue: any = 123;
    anyValue = 'anyValue'

    // unknown - 绕过赋值检查 => 禁止更改传递
    // 传递
    let unknownValue: unknown;
    unknownValue= 'unknownValue';

    let value1: unknown = unknownValue; // ok
    let value: any = unknownValue; // ok
    let value3: boolean = unknownValue; // 错误,禁止更改传递

    // void - 声明函数的返回值
    function voidFunction(): void {
        // 没有返回值的函数
    }

    // never - 永不返回
    function error(msg: string): never {
        throw new Error(msg);
    }
    // 这种情况会使用never 
    function loop(): never {
        while(true){}
    }
```

* object | Object | {} - 对象

```ts
    // object - 非原始类型
    interface ObjectConstructor {
        create(0: object | null): any;
    }
    const proto = {}
    Object.create(proto);

    // Object - 原型属性
    // Object.prototype上属性
    interface Object {
        constructor: Function;
        toString: string;
        valueOf(): Object;
    }

    // {} 空对象 - 没有成员的对象 描述一个空值
    const a = {} as A; // 作断言,否则以下代码报错
    a.class = 'es'; 
    a.age = 30;

```
###  二.接口 - interface
* 对行为的抽象,具体行为由类实现
```js
    interface Class {
        name: string;
        time: number;
    }
    let course: Class = {
        name: 'ts',
        time: 2
    }

    // 只读
     interface Class {
        readonly name: string;
        time: number;
    }

    // 任意
    interface Class {
        name: string;
        time: number;
        [PropName: string]: any;
    }

    // 面试题: 和js的引用不同
    let arr: number[] = [1,2,3,4];
    let ro: ReadonlyArray<number> = arr;

    ro[0] = 12; // Error - 赋值
    ro.push(5) // Error - 增加
    ro.length = 100; // Error - 长度改写
    arr = ro; // Error - 覆盖
```
### 三. 交叉类型 
```ts
    // 合并
    interface A {x: D}
    interface A {x: E}
    interface C {x: F}

    interface D {d: boolean}
    interface E {e: string}
    interface F {f: number}

    type ABC = A & B & C;
    let abc: ABC = {
        x: {
            d: false,
            e: 'ts',
            f: 5
        }
    }

    // 合并冲突
    interface A {
       c: string;
       d: string;
    }

    interface B {
        c: number;
        d: string;
    }
    type AB = A & B;
    // 合并的关系是且 => C: never
```
#### 四. 断言 - 类型声明 | 转换
```ts
    // 尖括号
    let anyValue: any = 'ts';
    let anyLength: number = (<string>anyValue).length; // 阶段性声明

    // as 声明
    let anyLength: number = (anyValue as string).length;

    // 非空判断
    type ClassTime = () => number;
    const start = (classTime: ClassTime | underfined) => {
        let num = classTime!(); // 确定一定不会为空
    } 

    // 面试题
    class tsClass: number | underfined = underfined;
    cosnt course: number = tsClass!;
    // 使用的意义 => 告知编译器,运行时下会被赋值
```

#### 五. 类型守卫
```ts
    interface Teacher {
        name: string;
        courses:string[];
        score: number;
    }

    interface Student {
        name: string;
        startTime: Date;
        score: string;
    }

    type Class = Teacher | Student;

    function startCourse(cls: Class) {
        if('courses' in cls) {
            // teacher的逻辑
        }
        if('startTime' in cls) {
            // student的逻辑
        }
    }

    function startCourse(cls: Class) {
        if(cls instanceof Teacher) {
            // teacher的逻辑
        }
        if(cls instanceof Student) {
            // student的逻辑
        }
    }

    function startCourse(name: string; score: string | number) {
        if(type score === 'number') {
            // teacher的逻辑
        }
        if(type score === 'string') {
            // student的逻辑
        }
    }
```

### 六. TS进阶
#### 1. 泛型 - 重用
```ts
    function startCalss<T, U>(name: T, score: U): T {
        return name + class;
    }
    console.log(startClass<string, number>('yy', 5));

    function startCalss<T, U>(name: T, score: U): string {
        return `${name}${class}`;
    }

    function startCalss<T, U>(name: T, score: U): T {
        return (name + String(score)) as any as T;
    }

    // T U K 键值 | V 值 | E节点
```

#### 2.装饰器 - decorator
```ts
    function Yunyin(target: Function): void {
        target.prototype.startClass = function(): vold{
            // start逻辑
        }
    } 
    // 类装饰器
    @Yunyin
    class Course {
        constructor() {
            // 业务逻辑
        }
    }

    // 属性装饰器
    function nameWrapper(target: any, key: string) {
        // 逻辑处理
        Object.defineProperty(target, key, {
            // 劫持
        })
    }
     class Course {
        constructor() {
            // 业务逻辑
        }

        @nameWrapper
        public name: string;
    }

    // 方法装饰器
    
```

#### 3. 原理解析
```ts
    // 1. 源码梳理
    let a: number = 2;
    // 2. scanner扫描器扫描 => 识别内容范围生成数据流
    [
        "let": "keytword",
        "a": "identifier",
        "=": "assignment",
        "2": "integer",
        ";": "eos" (end of statement)
    ]
    // number
    
    // 3. 解析器 parser 生成语法树 - AST抽象语法树
    {
        operation: "=",
        left: {
            keyword: 'var',
        }
    }

    // 4. 绑定器 binder 主要职责 创建symbols
    node.symbol

    // 5. 检查器 - checker 检查TS语法错误 => 检查器中进行的

    // 6. 发射器 emitter根据每个节点的检查结果产出node翻译成js

```