TypeScript学习笔记(二)——TypeScript 高级类型

瑞星  金牌会员 | 2024-8-24 17:52:44 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 533|帖子 533|积分 1599

目次
1. class 类
1.1 class 关键字的基本利用
1.2 类继承
1.3 类成员可见性
1.4 类成员只读修饰符
2. 类型兼容性
2.1 类型兼容性
2.2 接口兼容性
2.3 函数兼容性
3. 交织类型
4. 泛型
4.1 创建泛型函数
4.2 泛型约束
4.3 多个泛型的类型变量约束
4.4 泛型接口
4.5 泛型类
4.6 泛型工具类型
① 泛型工具类型 - Partial
② 泛型工具类型 - Readonly
③ 泛型工具类型 - Pick,>
④ 泛型工具类型 - Record,type>
5. 索引署名类型
6. 映射类型

概述:


  • TS 中的高级类型有很多,重点学习以下高级类型:

    • 1. class 类
    • 2. 类型兼容性
    • 3. 交织类型
    • 4. 泛型 和 keyof
    • 5. 索引署名类型 和 索引查询类型
    • 6. 映射类型

1. class 类

1.1 class 关键字的基本利用

   TypeScript 全面支持 ES2015 中引入的   class   关键字,并为其添加了类型注解和其他语法(好比,可见性修饰符等)。   
       表明:     

  • 根据 TS 中的类型推论,可以知道 Person 类的实例对象 p 的类型是 Person。
  • TS 中的 class,不仅提供了 class 的语法功能,也作为一种类型存在。
     实例属性初始化:      
           表明:      

  • 声明成员 age,类型为 number(没有初始值)。
  • 声明成员 gender,并设置初始值,此时,可省略类型注解(TS 类型推论 为 string 类型)。
       构造函数:           
               表明:         

  • 成员初始化(好比,age: number)后,才可以通过 this.age 来访问实例成员。
  • 需要为构造函数指定类型注解,否则会被隐式推断为 any;构造函数不需要返回值类型。
         实例方法:            
                   表明:         

  • 方法的类型注解(参数和返回值)与函数用法类似。
     1.2 类继承

           类继承的两种方式:         

  • extends(继承父类)
  • implements(实现接口)
           说明:         

  • JS 中只有 extends,而 implements 是 TS 提供的。
     ① extends(继承父类)
     

           表明:           

  • 通过 extends 关键字实现继承。
  • 子类 Dog 继承父类 Animal,则 Dog 的实例对象 dog 就同时具有了父类 Animal 和 子类 Dog 的所有属性和方法。
     ② implements(实现接口)
     

           表明:           

  • 通过 implements 关键字让 class 实现接口。
  • Person 类实现接口 Singable 意味着,Person 类中必须提供 Singable 接口中指定的所有方法和属性。
     1.3 类成员可见性

           类成员可见性:         

  • 可以利用 TS 来控制 class 的方法或属性对于 class 外的代码是否可见。
           可见性修饰符包罗:         

  • public(公有的)
  • protected(受掩护的)
  • private(私有的)。
           ①       public(公有的)         

  • public:表示公有的、公开的,公有成员可以被任何地方访问,默承认见性。
           
                       表明:            

  • 在类属性或方法前面添加 public 关键字,来修饰该属性或方法是共有的。
  • 由于 public 是默承认见性,以是,可以直接省略。
      ② protected(受掩护的)
      

  • protected:表示受掩护的,仅对其声明所在类和子类中(非实例对象)可见。
      

             表明:            

  • 在类属性或方法前面添加 protected 关键字,来修饰该属性或方法是受掩护的。
  • 在子类的方法内部可以通过 this 来访问父类中受掩护的成员,但是,对实例不可见!
      ③ private(私有的)
      

  • private:表示私有的,只在当前类中可见,对实例对象以及子类也是不可见的。
      

             表明:            

  • 在类属性或方法前面添加 private 关键字,来修饰该属性或方法是私有的。
  • 私有的属性或方法只在当前类中可见,对子类和实例对象也都是不可见的!
      1.4 类成员只读修饰符

             除了可见性修饰符之外,尚有一个常见修饰符就是:       readonly(只读修饰符)       。                           readonly        :              

  • 表示只读,用来防止在构造函数之外对属性举行赋值。
               
                               表明:                 

  • 利用 readonly 关键字修饰该属性是只读的,注意只能修饰属性不能修饰方法。
  • 注意:属性 age 后面的类型注解(好比,此处的 number)假如不加,则 age 的类型为 18 (字面量类型)。
  • 接口大概 {} 表示的对象类型,也可以利用 readonly
        2. 类型兼容性

        2.1 类型兼容性

                 ① 两种类型体系:               

  • Structural Type System(布局化类型体系)
  • Nominal Type System(标明类型体系)。
                 TS 采用的是布局化类型体系         ,也叫做 duck typing(鸭子类型),         类型检查关注的是值所具有的形状         。                          也就是说,在布局类型体系中,假如两个对象具有类似的形状,则认为它们属于同一类型。                        
                                   表明:                  

  • Point 和 Point2D 是两个名称不同的类。
  • 变量 p 的类型被显示标注为 Point 类型,但是,它的值却是 Point2D 的实例,并且没有类型错误。
  • 由于 TS 是布局化类型体系,只检查 Point 和 Point2D 的布局是否类似(类似,都具有 x 和 y 两个属性,属性类型也类似)。
  • 但是,假如在 Nominal Type System 中(好比,C#、Java 等),它们是不同的类,类型无法兼容。
         ② 成员多的可以赋值给少的(成员少的可以兼容成员多的)
                   注意:                  

  • 在布局化类型体系中,假如两个对象具有类似的形状,则认为它们属于同一类型,这种说法并不准确。
                   更准确的说法:                  

  • 对于对象类型来说,y 的成员至少与 x 类似,则 x 兼容 y(成员多的可以赋值给少的)。
         

                   表明:                  

  • Point3D 的成员至少与 Point 类似,则 Point 兼容 Point3D。
  • 以是,成员多的 Point3D 可以赋值给成员少的 Point。
         ③ 除了 class 之外,TS 中的其他类型也存在相互兼容的情况,包罗:
         

  • 接口兼容性
  • 函数兼容性 等。
         2.2 接口兼容性

         接口之间的兼容性,类似于 class。并且,class 和 interface 之间也可以兼容。
         

         

         2.3 函数兼容性

         函数之间兼容性比较复杂,需要思量:
         

  • 参数个数
  • 参数类型
  • 返回值类型。
         ① 参数个数
                   参数个数          ,参数多的兼容参数少的(大概说,          参数少的可以赋值给多的          )                           
                           
                                       表明:                     

  • 参数少的可以赋值给参数多的,以是,f1 可以赋值给 f2。
  • 数组 forEach 方法的第一个参数是回调函数,该示例中类型为:(value: string, index: number, array: string[]) => void。
  • 在 JS 中省略用不到的函数参数实际上是很常见的,这样的利用方式,促成了 TS 中函数类型之间的兼容性
  • 并且由于回调函数是有类型的,以是,TS 会主动推导出参数 item、index、array 的类型。
          ② 参数类型
                     参数类型           ,类似位置的参数类型要类似(原始类型)或兼容(对象类型)。                              
                                           表明:                     

  • 函数类型 F2 兼容函数类型 F1,由于 F1 和 F2 的第一个参数类型类似。
           

                       表明:                       

  • 注意,此处与前面讲到的接口兼容性冲突。
  • 技巧:

    • 将对象拆开,把每个属性看做一个个参数,则参数少的(f2)可以赋值给参数多的(f3)。

                       ③ 返回值类型                                  返回值类型            ,只关注返回值类型本身即可。                                 
                                 
                                               表明:                        

  • 假如返回值类型是原始类型,此时两个类型要类似,好比,左侧类型 F5 和 F6。
  • 假如返回值类型是对象类型,此时成员多的可以赋值给成员少的,好比,右侧类型 F7 和 F8
            3. 交织类型

            交织类型(&):功能类似于接口继承(extends),用于组合多个类型为一个类型(常用于对象类型)。
            好比:
            

                         表明:                        

  • 利用交织类型后,新的类型 PersonDetail 就同时具备了 Person 和 Contact 的所有属性类型。
                         相当于:                                    
                                                               交织类型(&)和接口继承(extends)的对比:                                       

  • 类似点:

    • 都可以实现对象类型的组合。

  • 不同点:

    • 两种方式实现类型组合时,对于同名属性之间,处置惩罚类型冲突的方式不同。

              

              

                             说明:                           

  • 以上代码,接口继承会报错(类型不兼容);交织类型没有错误,可以简单的理解为

                                                                                            4. 泛型

   泛型  是可以在  包管类型安全  前提下,让函数等  与多种类型一起工作  ,从而  实现复用  ,常用于:  

  • 函数、接口、class 中。
   需求:  

  • 创建一个 id 函数,传入什么数据就返回该数据本身(也就是说,参数和返回值类型类似)。

   好比,id(10) 调用以上函数就会直接返回 10 本身。但是,该函数只接收数值类型,无法用于其他类型。    为了能让函数能够接受任意类型,可以将参数类型修改为 any。但是,这样就失去了 TS 的类型掩护,类型不安全。   
         泛型   在   包管类型安全   (不丢失类型信息)的同时,可以   让函数等与多种不同的类型一起工作   ,机动可   复用   。        实际上,在 C#和 Java 等编程语言中,泛型都是用来实现可复用组件功能的主要工具之一。       4.1 创建泛型函数

       ① 创建泛型函数:         
                  表明:         

  • 语法:

    • 在函数名称的后面添加 <>(尖括号),尖括号中添加类型变量,好比此处的 Type。

  • 类型变量 Type,是一种特别类型的变量,它处置惩罚类型而不是值。
  • 该类型变量相当于一个类型容器,能够捕获用户提供的类型(具体是什么类型由用户调用该函数时指定)。
  • 由于 Type 是类型,因此可以将其作为函数参数和返回值的类型,表示参数和返回值具有类似的类型。
  • 类型变量 Type,可以是任意正当的变量名称。
               ② 调用泛型函数:              
               表明:         

  • 语法:

    • ·在函数名称的后面添加 <>(尖括号),尖括号中指定具体的类型,好比,此处的 number。

  • 当传入类型 number 后,这个类型就会被函数声明时指定的类型变量 Type 捕获到。
  • 此时,Type 的类型就是 number,以是,函数 id 参数和返回值的类型也都是 number。
         同样,假如传入类型 string,函数 id 参数和返回值的类型就都是 string。              这样,通过     泛型     就做到了让 id 函数与多种不同的类型一起工作,     实现了复用的同时包管了类型安全     。                 ③ 简化调用泛型函数            
                   表明:           

  • 在调用泛型函数时,可以省略 <类型> 来简化泛型函数的调用。
  • 此时,TS 内部会采用一种叫做类型参数推断的机制,来根据传入的实参主动推断出类型变量 Type 的类型。
  • 好比,传入实参 10,TS 会主动推断出变量 num 的类型 number,并作为 Type 的类型。
           推荐:         

  • 利用这种简化的方式调用泛型函数,使代码更短,更易于阅读。
           说明:         

  • 当编译器无法推断类型大概推断的类型不准确时,就需要显式地传入类型参数。
     4.2 泛型约束

           泛型约束      :         

  • 默认情况下,泛型函数的类型变量 Type 可以代表多个类型,这导致无法访问任何属性。
     好比,id('a') 调用函数时获取参数的长度:
     

           表明:         

  • Type 可以代表任意类型,无法包管一定存在 length 属性,好比 number 类型就没有 length。
           此时,就需要为泛型      添加约束      来      收缩类型      (缩窄类型取值范围)。                       添加泛型约束收缩类型,主要有以下两种方式:            

  • 指定更加具体的类型
  • 添加约束。
      ① 指定更加具体的类型
      

             好比,将类型修改为 Type[](Type 类型的数组),由于只要是数组就一定存在 length 属性,因此就可以访问了。                         ②        添加约束                  
                           表明:               

  • 创建描述约束的接口 ILength,该接口要求提供 length 属性。
  • 通过 extends 关键字利用该接口,为泛型(类型变量)添加约束。
  • 该约束表示:传入的类型必须具有 length 属性。
               注意:              

  • 传入的实参(好比,数组)只要有 length 属性即可,这也符合前面讲到的接口的类型兼容性。
       4.3 多个泛型的类型变量约束

               泛型的类型变量可以有多个,并且        类型变量之间还可以约束        (好比,第二个类型变量受第一个类型变量约束)。                               好比,创建一个函数来获取对象中属性的值:                        
                                   表明:                  

  • 添加了第二个类型变量 Key,两个类型变量之间利用(,)逗号分隔。
  • keyof 关键字接收一个对象类型,天生其键名称(可能是字符串或数字)的联合类型。
  • 本示例中 keyof Type 实际上获取的是 person 对象所有键的联合类型,也就是:'name' | 'age'。
  • 类型变量 Key 受 Type 约束,可以理解为:Key 只能是 Type 所有键中的任意一个,大概说只能访问对象中存在的属性。
         4.4 泛型接口

                   泛型接口          :                  

  • 接口也可以配合泛型来利用,以增加其机动性,增强其复用性。
         

         

                   表明:                  

  • 在接口名称的后面添加 <类型变量>,那么,这个接口就变成了泛型接口。
  • 接口的类型变量,对接口中所有其他成员可见,也就是接口中所有成员都可以利用类型变量。
  • 利用泛型接口时,需要显式指定具体的类型(好比,此处的 IdFunc<nunber>)。
  • 此时,id 方法的参数和返回值类型都是 number;ids 方法的返回值类型是 number[]。
                   实际上,JS 中的数组在 TS 中就是一个          泛型接口          。                           
                           
                                       表明:                    

  • 当我们在利用数组时,TS 会根据数组的不同类型,来主动将类型变量设置为相应的类型。
                     技巧:                    

  • 可以通过 Ctrl + 鼠标左键(Mac:option + 鼠标左键)来查察具体的类型信息。
          4.5 泛型类

                     泛型类           :                    

  • class 也可以配合泛型来利用。
                     好比,React 的 class 组件的基类 Component 就是泛型类,不同的组件有不同的 props 和 state。                              
                                           表明:                     

  • React.Component 泛型类两个类型变量,分别指定 props 和 state 类型。
                       ① 创建泛型类:                                 
                                               表明:                        

  • 类似于泛型接口,在 class 名称后面添加 <类型变量>,这个类就变成了泛型类。
  • 此处的 add 方法,采用的是箭头函数形式的类型书写方式。
                        
                                     类似于泛型接口,在创建 class 实例时,在类名后面通过 <类型> 来指定明白的类型。                                    4.6 泛型工具类型

                         泛型工具类型             :                        

  • TS 内置了一些常用的工具类型,来简化 TS 中的一些常见操纵。
                         说明:                        

  • 它们都是基于泛型实现的(泛型适用于多种类型,更加通用),并且是内置的,可以直接在代码中利用。
                         这些工具类型有很多,主要学习以下几个:                        

  • Partial<Type>
  • Readonly<Type>
  • Pick<Type, Keys>
  • Record<Keys, Type>
            ① 泛型工具类型 - Partial<Type>

            泛型工具类型 - Partial<Type> 用来构造(创建)一个类型,将 Type 的所有属性设置为可选。
                        
                                                   表明:                          

  • 构造出来的新类型 PartialProps 布局和 Props 类似,但所有属性都变为可选的。
             ② 泛型工具类型 - Readonly<Type>

                           泛型工具类型 -               Readonly<Type> 用来构造一个类型,将 Type 的所有属性都设置为 readonly(只读)              。                                                     
                                                       表明:                           

  • 构造出来的新类型 ReadonlyProps 布局和 Props 类似,但所有属性都变为只读的。
              

                             当我们想重新给 id 属性赋值时,就会报错:无法分配到 "id" ,由于它是只读属性。                                           ③ 泛型工具类型 - Pick<Type, Keys>

                                                泛型工具类型 -                  Pick<Type, Keys> 从 Type 中选择一组属性来构造新类型                 。                                                
                                                                   表明:                                   

  • Pick 工具类型有两个类型变量:

    • 表示选择谁的属性
    • 表示选择哪几个属性。

  • 其中第二个类型变量,假如只选择一个则只传入该属性名即可。
  • 第二个类型变量传入的属性只能是第一个类型变量中存在的属性。
  • 构造出来的新类型 PickProps,只有 id 和 title 两个属性类型。
                 ④ 泛型工具类型 - Record<Keys,Type>

                 泛型工具类型 - Record<Keys,Type> 构造一个对象类型,属性键为 Keys,属性类型为 Type。
                 

                                   表明:                                   

  • Record 工具类型有两个类型变量:

    • 表示对象有哪些属性
    • 表示对象属性的类型。

  • 构建的新对象类型 RecordObj 表示:

    • 这个对象有三个属性分别为a/b/c,属性值的类型都是 string[]。

                 5. 索引署名类型

                                   绝大多数情况下,我们都可以在利用对象前就确定对象的布局,并为对象添加准确的类型。                                                    利用场景:                                 

  • 当无法确定对象中有哪些属性(大概说对象中可以出现任意多个属性),此时,就用到索引署名类型了。
                 

                 

                                   表明:                                   

  • 利用 [key: string] 来约束该接口中答应出现的属性名称。表示只要是 string 类型的属性名称,都可以出现在对象中。
  • 这样,对象 obj 中就可以出现任意多个属性(好比,a、b 等)。
  • key 只是一个占位符,可以换成任意正当的变量名称。
  • 隐藏的前置知识:

    • JS 中对象({})的键是 string 类型的。

                                   在 JS 中数组是一类特别的对象,特别在                  数组的键(索引)是数值类型                  。并且,数组也可以出现任意多个元素。以是,在数组对应的泛型接口中,也用到了索引署名类型。                                                   
                                                                       表明:                                    

  • MyArray 接口模仿原生的数组接口,并利用 [n: number] 来作为索引署名类型。
  • 该索引署名类型表示:

    • 只要是 number 类型的键(索引)都可以出现在数组中,大概说数组中可以有任意多个元素。

  • 同时也符合数组索引是 number 类型这一前提。
                  6. 映射类型

                  映射类型:
                  

  • 基于旧类型创建新类型(对象类型),淘汰重复、提升开发服从。
                                     好比,类型 PropKeys 有 x/y/z,另一个类型 Type1 中也有 x/y/z,并且 Type1 中 x/y/z 的类型类似:                                                        
                                                                           这样书写没错,但 x/y/z 重复书写了两次。像这种情况,就可以利用映射类型来举行简化。                                                         
                                                                               表明:                                         

  • 映射类型是基于索引署名类型的,以是,该语法类似于索引署名类型,也利用了 []。
  • Key in PropKeys 表示 Key 可以是 PropKeys 联合类型中的任意一个,类似于 forin(let k in obj)。
  • 利用映射类型创建的新对象类型 Type2 和类型 Type1 布局完全类似。
  • 注意:

    • 映射类型只能在类型别名中利用,不能在接口中利用。

                                         映射类型                     除了根据联合类型创建新类型外,还可以根据对象类型来创建:                                                            
                                                                                   表明:                                          

  • 首先,先执行 keyof Props 获取到对象类型 Props 中所有键的联合类型即,'a' | 'b' | 'c'。
  • 然后,Key in ... 就表示 Key 可以是 Props 中所有的键名称中的任意一个。
                     

                                           实际上,前面讲到的                      泛型工具类型                      (好比,Partial<Type>)都                      是基于映射类型实现的                      。                                                                                       好比,Partial<Type> 的实现:                                                                  
                                                                  
                                                                                           表明:                                               

  • keyof T 即 keyof Props 表示获取 Props 的所有键,也就是:'a' | 'b' | 'c'。
  • 在 [] 后面添加 ?(问号),表示将这些属性变为可选的,以此来实现 Partial 的功能。
  • 冒号后面的 T[P] 表示获取 T 中每个键对应的类型。好比,假如是 'a' 则类型是 number;假如是 'b' 则类型是 string。
  • 最终,新类型 PartialProps 和旧类型 Props 布局完全类似,只是让所有类型都变为可选了。
                       刚刚用到的 T[P] 语法,在 TS 中叫做索引查询(访问)类型。
                       作用:用来查询属性的类型。
                       

                                               表明:                                             

  • Props['a'] 表示查询类型 Props 中属性 'a' 对应的类型 number。以是,TypeA 的类型为 number。
                                               注意:                                             

  • [] 中的属性必须存在于被查询类型中,否则就会报错。
                       索引查询类型的其他利用方式:同时查询多个索引的类型
                       

                                               表明:                                             

  • 利用字符串字面量的联合类型,获取属性 a 和 b 对应的类型,效果为: string | number。
                       

                                               表明:                                             

  • 利用 keyof 操纵符获取 Props 中所有键对应的类型,效果为: string | number | boolean。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

瑞星

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表