美文网首页
TypeScript全解:类型(下)

TypeScript全解:类型(下)

作者: littleyu | 来源:发表于2023-06-07 21:46 被阅读0次

    何时用enum类型

    当前端遇到这种需求的时候:

    前端需要显示后端返回的状态 1,2,3,4,还要传输这个值回去,

    但是我们经常会忘记这个值是什么意思,这个时候就可以使用 enum

    🌰:二进制权限

    enum Permission {
      None = 0,
      Read = 1 << 0, // 0001 // 这里的 << 是左移操作,1在二进制表示为 00..001,那么左移一位就是 00..010
      Write = 1 << 1, // 0010
      Delete = 1 << 2, //0100
      Manage = Read | Write | Delete, // 0111 // 这个的 | 是并操作,取二进制各个位置的 1 为结果
    }
    
    const user1: { permission: Permission } = { permission: 0b0101 };
    
    // 这里的 & 是与操作,取二进制各个位置同时为 1的为结果
    if ((user1.permission & Permission.Write) === Permission.Write) {
      console.log("拥有写权限")
    }
    if ((user1.permission & Permission.Manage) === Permission.Manage) {
      console.log("拥有管理权限")
    }
    

    何时不用 enum

    并不是说不能用,而是这时候用会显得很呆

    enum Fruit {
      apple = 'apple',
      banana = 'banana',
      pineapple = 'pineapple',
      watermelon = 'watermelon',
    }
    
    let f = Fruit.apple; // 这里甚至不能写 'apple'
    f = Fruit.pineapple
    

    几乎等价于

    type Fruit = 'apple' | 'banana' | 'pineapple' | 'watermelon'
    
    let f = 'apple'
    f = 'pineapple'
    

    结论

    • number enum √
    • string enum ×
    • other enum ×

    个人也觉得在 JS 中不太实用,在没有 enum 的时候 JS 程序员就在用对象表示了,而且还比不上对象好用:

    const PERMISSION = {
      0: 'read',
      1: 'write',
      2: 'delete',
      3: 'manage'
    }
    

    也几乎是一样的效果,无论有没有 enum,也能用的好好的,最多可能性能上没有 enum 好,又不是不能用,建议是能不用就不用

    type与interfacer的区别

    何时用 type?

    答案是什么时候都可以,几乎没有不能用的场合

    type 又叫类型别名,英文 Type Alias,简单来说就给其他类型取个名字

    比如说我们可以给 string 换个名字,以下这样几乎是等价的:

    type Name = string;
    
    const a: Name = 'hi'
    

    等等其他复杂类型都可以用 type,这里只说一种特殊情况,带有属性的函数:

    type Fn = (a: number) => void // 纯函数,没有属性
    type FnWithProp = {
      (a: number): void; // 这里来声明函数,语法很奇怪把~
      prop: string;
    }
    

    为何要叫做类型别名,不叫做类型声明

    因为 ts 一开始并没有想要记住这个名字,比如说:

    type A = string;
    type B = A
    

    请问此时 B 的类型是什么,应该是 A 把,
    但是其实是 string,A 没有被记住

    何时用 interface

    interface 又叫声明接口,

    接口是什么?你翻过的 JS 教程中,从来没有提到过这个单词,那是那个理论讲到这个呢?是面向对象。ts 为了满足这些人,搞了一个接口出来。

    此接口非彼接口,还是对象,描述对象的属性(declare the shapes of objects)

    // 描述普通对象
    interface A {
      name: string;
      age: number;
    }
    
    // 描述数组
    interface A extends Array<string>{
      name: string;
    }
    // 如何用 type 实现上述效果
    type A2 = Array<string> & { name: string; }
    
    // 描述函数
    interface Fn {
      (a: number): void;
    }
    // 描述带成员的函数
    interface Fn {
      (a: number): void;
      prop: string;
    }
    
    // 描述日期对象
    interface D extends Date {}
    

    type 不可重新赋值

    这个既是优点也是缺点

    type A = number;
    
    A = string // 报错,没有这种语法
    

    好处是提升效率,声明什么就是什么,不用管以后你还会变,当然带来的缺点则是不好拓展

    interface 能自动合并

    比如在我们经常使用的 axios 上:

    // custom.d.ts
    import { AxiosRTequestConfig } from 'axios'
    
    declare module 'axios' {
      export interface  AxiosRequestConfig {
        _autoLoading?: boolean;
      }
    }
    
    axios.get('/list', {
      _autoLoading: true // 拓展出来的
    })
    

    比如拓展 String:

    declare global {
      interface String {
        newFn(x: string): void
      }
    }
    
    const s = 'string'
    s.newFn('xxx') // 此时不会报错
    

    小结

    • 区别1:
      • interface 只描述对象
      • type 则描述所有数据
    • 区别2:
      • type 只是别名
      • interface 则是类型声明
    • 区别3:
      • 对外 API 尽量用 interface,方便拓展
      • 对内 API 尽量用 type,防止代码分散

    看起来 type 的应用范围更广,且包括 interface,看起来 interface 没有必要出现。其实是原因之一为了迎合面向对象粉丝的需求

    听说 type 不能继承?

    瞎说!

    继承的本质是什么?就是一个东西拥有另一个东西的属性

    这个东西很容易实现,比如说复制

    那 type 怎么拓展?

    type MyAxiosRTequestConfig  = AxiosRTequestConfig  & { _autoLoading?: boolean; }
    

    几乎是一样的效果,而且更安全,不会修改到原先的类型。

    总结

    相关文章

      网友评论

          本文标题:TypeScript全解:类型(下)

          本文链接:https://www.haomeiwen.com/subject/jcyvedtx.html