TypeScript(四)枚举类型(Enum Types),类型别名(Type),运算符

一、枚举类型

使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript支持数字的和基于字符串的枚举。
枚举类型的特点

  • 可以给一组数值取上一个更好理解的名字;
  • 一个枚举中只会存在几个固定的值,并不会出现超出范围的可能性;
    在很多编程语言中都会有枚举这种数据结构,但是在 JavaScript 中没有这种枚举数据结构,很多时候都是用一个对象来模拟枚举,如下:
    const PostStatus = {
      name: '迪西',
      age: 9,
      className: '三年级'
    }
    
    在 Typescript 当中可以用 enum 关键词声明一个枚举,{ } 里面是枚举的值,注意的是用 = 号,使用方式跟对象一样。
    enum PostStatus {
      name = '迪西',
      age = 9,
      className = '三年级'
    }
    
  1. 数字枚举
    枚举值自动基于前一个值自增,如果没指定具体数值,则从 0 开始。
    enum PostStatus1 {
      Draft,
      Draft1 = 5, 
      Draft2 = 7,
      Draft3
    }
    console.log(PostStatus1.Draft) // 0
    console.log(PostStatus1.Draft1) // 5
    console.log(PostStatus1.Draft2) // 7
    console.log(PostStatus1.Draft3) // 8
    
  2. 字符串枚举
    字符串枚举无法自增,需要手动添加,字符串枚举不太常见, 如果不添加会报错。
    enum PostStatus1 {
      Str = 'a',
      Str1 = 'b', 
      Str2 = 'c',
      Str3 = 'd',
    }
    console.log(PostStatus1.Str) // a
    console.log(PostStatus1.Str1) // b
    console.log(PostStatus1.Str2) // c
    console.log(PostStatus1.Str3) // d
    
    在这里插入图片描述
  3. 计算的和常量成员
    每个枚举成员都带有一个值,它可以是 常量或 计算出来的。 当满足如下条件时,枚举成员被当作是常量:
    • 它是枚举的第一个成员且没有初始化器,这种情况下它被赋予值 0:
    enum PostStatus1 {
      Draft,
    }
    console.log(PostStatus1.Draft) // 0
    
    • 它不带有初始化器且它之前的枚举成员是一个 数字常量。 这种情况下,当前枚举成员的值为它上一个枚举成员的值加1。
    enum PostStatus1 {
      Draft = 1,
      Draft1, 
      Draft2,
    }
    console.log(PostStatus1.Draft) // 1
    console.log(PostStatus1.Draft1) // 2
    console.log(PostStatus1.Draft2) // 3
    
    • 枚举成员使用 常量枚举表达式初始化。 常数枚举表达式是TypeScript表达式的子集,它可以在编译阶段求值。 当一个表达式满足下面条件之一时,它就是一个常量枚举表达式:
      ①: 一个枚举表达式字面量(主要是字符串字面量或数字字面量)
      ②: 一个对之前定义的常量枚举成员的引用(可以是在不同的枚举类型中定义的)
      ③: 带括号的常量枚举表达式
      ④: 一元运算符 +, -, ~其中之一应用在了常量枚举表达式
      ⑤: 常量枚举表达式做为二元运算符 +, -, *, /, %, <<, >>, >>>, &, |, ^的操作对象。 若常数枚举表达式求值后为 NaN或 Infinity,则会在编译阶段报错。
    enum FileAccess {
      None,
      Read  = 1 << 1,
      Write = 1 << 2,
      ReadWrite  = Read | Write,
      G = "123".length
    }
    console.log(FileAccess.None) // 0
    console.log(FileAccess.Read) // 2
    console.log(FileAccess.Write) // 4
    console.log(FileAccess.ReadWrite) // 6
    console.log(FileAccess.G) // 3
    
    所有其它情况的枚举成员被当作是需要计算得出的值。
  4. 常量枚举
    如果我们确认我们代码中不会使用索引器的方式去访问枚举,那推荐使用常量枚举,常量枚举:enum 前面加个关键词 const。
    const enum Enum {
        A = 1,
        B = A * 2
    }
    
    常量枚举只能使用常量枚举表达式,并且不同于常规的枚举,它们在编译阶段会被删除。 常量枚举成员在使用的地方会被内联进来。 之所以可以这么做是因为,常量枚举不允许包含计算成员。
    编译前
    const enum Directions {
        Up,
        Down,
        Left,
        Right
    }
    let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]
    
    编译后
    var directions = [0 /* Directions.Up */, 1 /* Directions.Down */, 2 /* Directions.Left */, 3 /* Directions.Right */];
    
  5. 枚举类型会影响编译结果
    枚举类型会入侵到运行时的代码,也就是说它会影响编译后的结果,会编译成一个双向的键值对对象,目的是可以让我们动态的根据枚举值去或者枚举的名称,也就是说可以通过索引器的方式去访问对应的枚举名称。
    编译前
    enum Directions {
      Up,
      Down,
      Left,
      Right
    }
    
    const post = {
      title: 'Hello TypeScript',
      content: 'TypeScript is a typed superset of JavaScript.',
      positionUp: Directions.Up
    }
    
    编译后
    var Directions;
    (function (Directions) {
        Directions[Directions["Up"] = 0] = "Up";
        Directions[Directions["Down"] = 1] = "Down";
        Directions[Directions["Left"] = 2] = "Left";
        Directions[Directions["Right"] = 3] = "Right";
    })(Directions || (Directions = {}));
    var post = {
        title: 'Hello TypeScript',
        content: 'TypeScript is a typed superset of JavaScript.',
        positionUp: Directions.Up
    };
    

二、Type 类型别名

Type又叫类型别名(type alias),作用是给一个类型起一个新名字,
不仅支持interface定义的对象结构,还支持基本类型、联合类型、交叉类型、元组等任何你需要手写的类型。

type num = number; // 基本类型
type stringOrNum = string | number; // 联合类型
type person = {name: string}; // 对象类型
type user = person & { age: number } // 交叉类型
type data = [string, number]; // 元组
type fun = () => void; // 函数类型
  1. type和interface的相同点:
    • 都可以用来描述一个对象或者函数
      interface
    interface user {name: string; age:number}; // 对象
    interface setUser {(name: string; age:number):void}; // 函数
    
    type
    type user = {name: string; age:number}; // 对象 
    type setUser = (name: string; age:number):void;//函数
    
    • 都可以进行拓展
      interface可以扩展,
    interface userName {
     name: string;
    }
    interface user extends userName {
     age: number
    }
    let stu:user = {name: 'wang', age: 10}
    
    type可以通过交叉实现interface的extends行为
    type userName = {
       name: string;
    }
    type user = userName & {age: number}
    let stu:user = {name: 'wang', age: 18}
    
    interface可以extends type,
    type name = {
      name: string;
    }
    interface user extends name {
      age: number;
    }
    let stu:user = {name: 'wang', age: 89}
    
    type也可以与interface类型交叉 。
    interface name {
      name: string;
    }
    type user = name & {
      age: number;
    }
    let stu:user = {name:'wang', age: 18}
    
  2. type和interface的不同点:
    • type可以做到而interface不能做到
      type可以声明基本类型
    type name = string;
    
    type可以声明联合类型
    type name = string | number;
    
    type可以声明元祖类型
    type infoList = [string, number];
    
    type可以通过typeof操作符来声明
    type typeObj = typeof someObj;
    
    • interface 可以做到而 type 不能做到
      interface 可以声明合并。
    
    interface info {
        name: string
    }
    interface info {
        age: number
    }
    /*
        info 实际为 {
            name: string
            age: number
        }
    */
    
    如果是 type 的话,就会报重复定义的警告,因此是无法实现声明合并的。
    在这里插入图片描述
  3. 使用建议
  • 推荐使用 interface,其他无法满足需求的情况下用 type。但是因为联合类型和交叉类型是比较常用的,所以避免不了大量使用 type 的场景,一些复杂类型也需要通过组装后形成类型别名来使用。
  • 如果想保持代码统一,还是可选择使用 type。通过上面的对比,type 其实可涵盖 interface 的大部分场景。
  • 对于 React 或Vue 组件中 props 及 state,推荐使用 type,这样能够保证使用组件的地方不能随意在上面添加属性。如果有自定义需求,可通过 HOC(高阶组件)二次封装。
  • 编写三方库时使推荐使用 interface,其更加灵活自动的类型合并可应对未知的复杂使用场景。

三、运算符

运算符用于执行程序代码运算

  1. 算术运算符
    算术运算符用于对数字进行基本的算术计算。
    假设:x = 5

    运算符描述例子x运算结果y运算结果
    +加法(用于将两个数字相加。)y=x+5510
    -减法(用于从一个数字中减去另一个数字。)y=x-253
    *乘法(用于将两个数字相乘。)y=x*2510
    /除法(用于将一个数字除以另一个数字。)y=15/x53
    %取模(余数)(用于计算一个数字除以另一个数字后的余数。)y=x%251
    ++自增 (用于将一个数字增加 1。)y = x++55
    ++自增y= ++x56
    - -自减(用于将一个数字减少 1)y= x–55
    - -自减y= --x54

    注:在进行自增(++)的运算时,如果运算符(++)放在操作数的前面是先进行自增运算,再进行其他运算。
    若是运算符放在操作数的后面则是先进行其他运算再进行自增运算。同理可知自减(–)运算亦是如此。

    //	加法
    // const x:number = 5;
    // let y:number = x + 5
    // console.log(y) // 10
    
    // 减法
    // const x:number = 5;
    // let y:number = x - 2
    // console.log(y) // 3
    
    // 乘法
    // const x:number = 5;
    // let y:number = x * 2
    // console.log(y) // 10
    
    // 除法
    // const x:number = 5;
    // let y:number = 15 / x
    // console.log(y) // 3
    
    // 取模(余数)
    // const x:number = 5;
    // let y:number = x%2
    // console.log(y) // 1
    
    // 自增 ++在后
    // let x:number = 5;
    // let y:number = x++;
    // console.log(y) // 5
    // 自增 ++在前
    // let x:number = 5;
    // let y:number = ++x;
    // console.log(y) // 6
    
    //两个++联用
    // let x:number = 5;
    // let y:number = x++;
    // y = ++x;
    // console.log(y) // 7
    
    // let x:number = 5;
    // let y:number = ++x;
    // y = x++;
    // console.log(y) // 6
    
    // -- 在后
    // let x:number = 5;
    // let y:number = x--;
    // console.log(y) // 5
    // -- 在前
    // let x:number = 5;
    // let y:number = --x;
    // console.log(y) // 4
    
  2. 逻辑运算符
    逻辑运算符用于测定变量或值之间的逻辑 并生成布尔值结果。
    给定 x=6 以及 y=3,下表解释了逻辑运算符:

    运算符描述例子
    &&(并且)用于在两个条件都为真时返回真。(x < 10 && y > 1)为 true
    2个竖线(这里表达不出来)(或者 )用于在至少一个条件为真时返回真。(x5 或者 y5) 为 false
    ! (非)用于对表达式取反。!(x==y) 为 true
    // && 并且
    // let a: number = 10;
    // let b: number = 6;
    // let result: boolean = a > 8 && b > 5; 
    // console.log(result) // true
    
    // || 或者
    // let a: number = 10;
    // let b: number = 6;
    // let result: boolean = a > 8 || b > 7;  // a大于8或者b大于7 有一个就返回true
    // console.log(result) // true
    
    // !非
    // let a: number = 10;
    // let b: number = 6;
    // let result: boolean = !(a == b); 
    // console.log(result) // true
    
  3. 关系运算符
    关系运算符用于计算结果是否为 true 或者 false。

    运算符描述比较返回值
    ==(相等)用于比较两个值是否相等。(5 == 8)false
    !=(不等)用于比较两个值是否不相等。(5 != 8)true
    > (大于)用于判断左边的值是否大于右边的值。(5 > 8)false
    < (小于)用于判断左边的值是否小于右边的值。(5 < 8)true
    >=(大于等于)用于判断左边的值是否大于等于右边的值。(5 >= 8)false
    <= (小于等于)用于判断左边的值是否小于等于右边的值。(5 <= 8)true
    var num1:number = 5;
    var num2:number = 9;
     
    console.log("num1 的值为: "+num1); // num1 的值为: 5
    console.log("num2 的值为:"+num2); // num2 的值为:9
     
    var res = num1>num2 
    console.log("num1 大于n num2: "+res) // num1 大于n num2: false
     
    res = num1<num2 
    console.log("num1 小于 num2: "+res)  // num1 小于 num2: true
     
    res = num1>=num2 
    console.log("num1 大于或等于  num2: "+res) // num1 大于或等于  num2: false
     
    res = num1<=num2
    console.log("num1 小于或等于 num2: "+res)   // num1 小于或等于 num2: true
     
    res = num1==num2 
    console.log("num1 等于 num2: "+res)  // num1 等于 num2: false
     
    res = num1!=num2  
    console.log("num1 不等于 num2: "+res) // num1 不等于 num2: true
    
  4. 位运算符
    位操作是程序设计中对位模式按位或二进制数的一元和二元操作。

    运算符描述例子类似于结果十进制
    &AND,按位与处理两个长度相同的二进制数,两个相应的二进位都为 1,该位的结果值才为 1,否则为 0。x = 5 & 10101 & 000100011
    竖线OR,按位或处理两个长度相同的二进制数,两个相应的二进位中只要有一个为 1,该位的结果值为 1。x = 5 竖线 10101 & 000101011
    ~取反,取反是一元运算符,对一个二进制数的每一位执行逻辑反操作。使数字 1 成为 0,0 成为 1。x = ~ 5~01011010-6
    ^异或,按位异或运算,对等长二进制模式按位或二进制数的每一位执行逻辑异按位或操作。操作的结果是如果某位不同则该位为 1,否则该位为 0。x = 5 ^ 10101 ^ 000101004
    <<左移,把 << 左边的运算数的各二进位全部左移若干位,由 << 右边的数指定移动的位数,高位丢弃,低位补 0。x = 5 << 10101 << 1101010
    >>右移,把 >> 左边的运算数的各二进位全部右移若干位,>> 右边的数指定移动的位数。x = 5 >> 10101 >> 100102
    >>>无符号右移,与有符号右移位类似,除了左边一律使用0 补位。x = 2 >>> 10010 >>> 100011
    var a:number = 2;   // 二进制 10 
    var b:number = 3;   // 二进制 11
        
    var result; 
            
    result = (a & b);     
    console.log("(a & b) => ",result) // (a & b) =>  2
                
    result = (a | b);          
    console.log("(a | b) => ",result)  // (a | b) =>  3
            
    result = (a ^ b);  
    console.log("(a ^ b) => ",result); // (a ^ b) =>  1
        
    result = (~b); 
    console.log("(~b) => ",result); // (~b) =>  -4
     
    result = (a << b); 
    console.log("(a << b) => ",result); // (a << b) =>  16
     
    result = (a >> b); 
    console.log("(a >> b) => ",result); // (a >> b) =>  0
     
    result = (a >>> 1); 
    console.log("(a >>> 1) => ",result); // (a >>> 1) =>  1
    
  5. 赋值运算符
    赋值运算符用于给变量赋值。
    给定 x=10 和 y=5,下面的表格解释了赋值运算符:

    运算符描述例子范例x值
    =(赋值)用于将右边的值赋给左边的变量x = yx = yx=5
    +=(先进行加运算后赋值)用于将右边的值与左边的变量相加,并将结果赋给左边的变量。x += yx = x + yx = 15
    -=(先进行减运算后赋值)用于将右边的值从左边的变量中减去,并将结果赋给左边的变量。x -= yx = x - yx = 5
    *=(先进行乘运算后赋值)用于将右边的值与左边的变量相乘,并将结果赋给左边的变量。x *= yx = x * yx = 50
    /= (先进行除运算后赋值)用于将左边的变量除以右边的值,并将结果赋给左边的变量。x /= yx = x / yx = 2

    类似的逻辑运算符也可以与赋值运算符联合使用:<<=, >>=, >>=, &=, |= 与 ^=。

    var a: number = 12 
    var b:number = 10  
     
    a = b 
    console.log("a = b: "+a) // a = b: 10
     
    a += b
    console.log("a+=b: "+a) // a+=b: 20
     
    a -= b 
    console.log("a-=b: "+a) // a-=b: 10
     
    a *= b 
    console.log("a*=b: "+a) // a*=b: 100
     
    a /= b 
    console.log("a/=b: "+a) // a/=b: 10
     
    a %= b 
    console.log("a%=b: "+a) // a%=b: 0
    
  6. 三元/条件运算符
    三元运算有 3 个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
    Test ? expr1 : expr2

    Test - 指定的条件语句
    expr1 - 如果条件语句 Test 返回 true 则返回该值
    expr2 - 如果条件语句 Test 返回 false 则返回该值

    var num:number = -2 
    var result = num > 0 ? "大于 0" : "小于 0,或等于 0" 
    console.log(result) // 小于 0,或等于 0
    
  7. 字符串运算符:连接运算符 (+)
    运算符可以拼接两个字符串,

    var msg:string = "codebaoku"+".com" 
    console.log(msg) // codebaoku.com
    
  8. 类型运算符

    • typeof 运算符 typeof 是一元运算符,返回操作数的数据类型。
    var num = 12 
    console.log(typeof num);   // number
    
    • instanceof 运算符检查一个对象是否是一个特定的构造函数创建的,或者是否实现了一个特定的接口。它只能用在表达式中,不能用在类型上下文中。它返回一个布尔值,表示对象是否属于构造函数的原型链。例如:
    interface Animal {
        eat(): void;
    }
     
    class Dog implements Animal {
        eat() {
            console.log("Dog eats");
        }
        bark() {
            console.log("Dog barks");
        }
    }
     
    let dog = new Dog();
    console.log(dog instanceof Dog); // true
    console.log(dog instanceof Animal); // true
    

    typeof 和 instanceof 的使用场景也不同:

    • 使用 typeof 来获取或检查简单的内置类型,例如字符串,数字,布尔值等。
    • 使用 instanceof 来检查自定义的类型,例如类,接口等。
    • 使用 instanceof 来检查复杂的内置类型,例如数组,正则表达式等。
  • 31
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值