TS高级类型

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

class类

类型兼容性

交叉类型

泛型和keyof

索引签名类型和索引查询类型

映射类型

class类
TS全面知识ES6中引入的class关键字  并为其添加了类型注解和其他语法(比如,可见性修饰符等)

class基本使用:
    class Person{}
    const p=new Person()
    
解释:
    根据TS中的类型推论 可以知道Person类的实例对象p的类型是Person
    TS中的class 不仅提供了class的语法功能 也作为一种类型存在

示例属性初始化:
    class Person {
        age:number
        gender='男'  //gender:string='男'    
    } 
解释:
    声明成员age 类型为number (没有初始值)
    声明成员gender 并设置初始值 此时 可省略类型注解(TS类型推论为string类型)

class Person {
  age:number
  gender:string
  constructor(age:number,gender:string){
   this.age=age
    this.gender=gender
  }
} 
解释:
		成员初始化(比如 age:number),才可以通过this.age来访问实例成员
		需要为构造函数指定类型注解,否则会被隐式推断为any,构造函数不需要返回值类型

		
class Point {
  x=10
  y=10
  fn(n:number):void{
    this.x*=n
    this.y*=n
  }
}
解释: 方法的类型注解(参数和返回值)与函数用法相同

类继承的两种方式:
			extends(继承父类)
			implements(实现接口)
说明:JS中只有extends 而iimplements是TS提供的

通过	extends(继承父类)
class Animal{
   move(){console.log('i`m running')}
 }
class Dog extends Animal{
  bark(){console.log('wang~')}
}
const dog=new Dog()
	解释:
			通过extends关键字 实现继承
      子类Dog继承父类Animal 则Dog的实例对象dog就同时具有父类Animal和子类Dog的属性和方法
      
 通过 	implements(实现接口)
	interface Singable{
    sing():void
  }
   class Person implements Singable{
     sing(){
       console.log('呦吼吼~~~~~')
     }
   }
解释:
	通过implements关键字让class实现接口
  Person类实现接口Singable意味着 Person类中必须提供Singable接口中指定的所有方法和属性
  
 类成员可见性:可以使用TS来控制class的方法或属性对于class外的代码是否可见
 可见性修饰符包括:public(公有的:默认就是公有 可以省略) protected(受保护的)  private(私有的)

1.public:表示公有的 公开的 公有成员可以被任何地方访问 默认可见性
	class Animal{
    pubilc move(){
      console.log('i`m running~~')
    }
  }
解释:
	在类属性或方法前面添加public关键字 来叙事该属性或方法是共有的
  因为public是默认可见性 所以 可以直接省略
  
2.protected: 表示受保护的 仅对期声明所在类和子类中(非实例对象)可见
	class Animal{
    protected move(){console.log('我就不动')}
    public go(){this.move()}
  }
class Dog extends Animal{
  dogGo(){this.move()}
}
const dog=new Dog()
可以访问到:dog.go()  dog.dogGo()
不可以访问: dog.move() //属性“move”受保护,只能在类“Animal”及其子类中访问。
解释:
	在雷属性或方法前面添加 protected 关键字 来修饰该属性或方法是受保护的
  在子类方法内部可以通过this来访问父类中受保护的成员 但是  对实例不可见!!!!!

3. private:表示私有的 只在当前类中可见  对实例对象以及子类也是不可见的
	class Animal{
    private move(){console.log('就不!!!')}
    walk(){this.move()}
  }
解释:
		在类属性或方法面前添加private关键字 来修饰该属性或方法是私有的
    私有的属性或方法 只在当前类中可见 对子类和实例对象也都是不可见的
 
 除了可见性修饰符外,还有一个常见的修饰符就是:readonly(只读修饰符)
readonly:表示只读 用来方式在狗仔函数之外对属性进行赋值
<!!!!注意 只要是readonly 来修饰的属性,必须手动提供明确的类型>
	class Person{
    readonly age:number=18
    constructor(age:number){
      this.age=age
    }
  }
	解释:
		使用readonly关键字修饰该属性是只读的 注意只能修饰属性 不能修饰方法
    注意:age后边的类型注解(比如number)如果不加 则age的类型为 18(字面量类型)
		接口或者{}表示的对象类型 也可以使用readonly
    const obj: { readonly name: string } = {
    name: 'xiaohong'
			}
交叉类型
交叉类型(&):功能类似于接口继承(extends) 用于组合多个类型为同一个类型(常用于对象类型).
interface Person {name:string}
interface Contact {phone:string}
type PersonDetail=Person&Contact
let obj:PersonDetail={
  name:'rose',
  phone:'13133111133'
}
解释: 使用交叉类型后 新的类型PersonDetail就同时具备了 Person和Contact的所有属性类型.
相当于:
	type PersonDetail={name:string;phone:string}


交叉类型和接口类型的对比
	交叉类型(&)和接口继承(extends)的对比:
		相同点:都可以实现对象类型的组合
    不同点:两种方式实现类型组合时,对于同名属性之间 处理类型冲突的方式不同
    
    接口继承:
		interface A{ fn:(value:number)=>string}
		interface B extends A{ fn:(value:string)=>string} //报错 类型不兼容

		interface A {fn:(value:number)=>string}
		interface B {fn:(value:string)=>string}
  	 type C=A&B
	说明:以上代码.接口继承会报错(类型不兼容);交叉类型没有错误 可以简单的理解为:
		fn:(value:string|number)=>string


泛型
泛型是可以在保护类型安全前提下,让函数与多种类型一起工作 从而实现复用 常用于 函数 接口 calss 中
泛型在保证类型安全(不丢失类型信息)的同时,可以让函数等与多种不同的类型一起工作,灵活可复用

创建一个泛型函数:
	function id<Type>(value:Type):Type {return value}
解释:
	语法:在函数名称的后面 添加<>(尖括号) 尖括号中添加类型变量,比如此处的Type.
  类型变量Type 是一种特殊类型的变量 他处理类型 而不是值
  该类型变量相当于一个类型容器 能够捕获用户提供的类型(具体是什么类型由用户调用该函数时指定)
	因为Type是类型 因此可以将其作为函数参数和返回值的类型,表示参数和返回值具有相同的类型
	类型变量Type 可以是任意合法的变量名称
  
 调用泛型函数:
	function	 id<Type>(value:Type):Type{return value}
	const num=id<number>(12) //const num:number
  const str=id<string>("a") //const str:string
  解释:
			语法:在函数名称的后面 添加<> (尖括号) 尖括号中指定具体的类型 比如 此处的number
      当传入类型number后 这个类型就会被函数声明时 指定的类型变量Type捕获到.
      此时 Type的类型就是number 所以 函数id参数和返回值的类型也都是number
      同样 如果传入string类型  函数id 参数和返回值的类型就都是string
      这样 通过泛型就做到了 让id函数与多种不同的类型一起工作 实现了复用的同时 保证类类型安全