3、TypeScript高级数据类型

1、介绍

上一篇(TypeScript常见的数据类型):http://t.csdn.cn/UjGrn

TS中除了上篇文档中描述的常见数据类型之外,还有很多高级数据类型,本文档列举一些常用的类型。

  • class 类定义
  • 类型兼容性
  • 交叉类型
  • 泛型 和 keyof
  • 索引签名类型 和 索引查询类型
  • 映射类型

2、使用

一、class 类定义

TS全面支持ES6规范中的class类定义,并且对其进行了增强,如添加了类型注解、实现接口、可见性修饰符等等。

/**
 * TS中的class,不仅提供了class的语法功能,定义的类也作为一种类型存在
 */
class Person{
    name: string;
    age: number;
    constructor(name: string,age: number){
        this.name = name;
        this.age = age;
    }
}
const p: Person = new Person("张三",18);

实现接口:ES规范中的class类可以继承父类,TS对其进行了增强,使其可以实现接口。

/**
 * class类通过implements关键字实现接口
 * 子类必须显示提供父接口中所有属性
 * 子类可以同时实现多个接口,使用 , 分隔
 */
interface Person{
    name: string,
    say: Function
}
interface Behave{
    eat(): void
}

class Student implements Person,Behave{
    name = '姓名';
    say = ()=>{
        console.log('say hello');
    }
    eat = ()=>{
        console.log('吃饭');
    }
}

可见性修饰符:TS对class类 属性/方法 添加了可见性修饰符,用来控制class的方法或属性对于class外的代码是否可见。

可见性修饰符包括:1 public(公共的,默认) 2 protected(受保护的) 3 private(私有的)。

public修饰符

/**
 * public:表示该属性为公开的,在任何地方均可访问(默认修饰符,可省略)
 * 当前类内部、子类、当前类外部均可访问
 */
class Person{
    public name: string = '名字'; //同 name: string; 写法作用一致
    getName = ()=>{
        return this.name; //本类中可访问
    }
}

let p = new Person();
console.log(p.name);//Person类外部也可访问

protected修饰符

/**
 * protected:表示受保护的,仅对其声明所在类和子类中(非实例对象)可见。
 */
class Person{
    protected name: string = '名字'; 
    protected getName = ()=>{
        return this.name; //本类中可访问
    }
}

class Student extends Person{
    printName = ()=>{
        console.log(this.name); //子类中可访问
    }
}

let s = new Student();
s.printName();
let p = new Person();
//console.log(p.name); //Person类外部不可访问,编译报错

private修饰符

/**
 * private:表示私有的,只在当前类中可见,对实例对象以及子类也是不可见的。
 */
class Person{
    private name: string = '名字'; 
    private getName = ()=>{
        return this.name; //本类中可访问
    }
}

class Student extends Person{
    printName = ()=>{
        //console.log(this.name); //编译报错,子类无法访问
    }
}

let s = new Student();
//s.name; //Person类外部不可访问,编译报错

readonly修饰符:表示属性只读,用来防止在构造函数之外对属性进行赋值

class Person{
    readonly name: string = '名字'; 

    constructor(name: string){
        this.name = name; //构造函数可以为readonly属性赋初值
    }

    setName = (name: string){
        //this.name = name; //编译报错:Cannot assign to 'name' because it is a read-only 
    }
}

二、类型兼容性

两种类型系统:1:Structural Type System(结构化类型系统),2:Nominal Type System(标明类型系统)。

TS采用的是结构化类型系统,类型检查关注的是值所具有的结构,如果两个对象具有相同的结构,则认为它们属于同一类型。

标明类型系统,两个对象的类型若要相等,就必须具有相同“名字”的类型(Java、C#)。

class类兼容

class Position{x: number=0;y: number=0}
class Position2{x: number=0;y: number=0}
class Position3{x: number=0;y: number=0;z: number=0}

//Position、Position2结构相同,所以类型相同
const p: Position = new Position2(); 
/**
 * Position3包含Position2所有的结构(Position2⊆Position3)
 * 所以Position2可以作为Position3的对象的类型,反之则不成立
 */
const p2: Position2 = new Position3();

接口兼容

interface Position{x: number;y: number}
interface Position2{x: number;y: number}
interface Position3{x: number;y: number;z: number}

/**
 * 接口兼容性与class类兼容性类似
 */
let p: Position = {x:0,y:0};
let p2: Position2 = p;
let p3: Position3 = {x:0,y:0,z:0};
p2 = p3;

函数兼容

函数兼容性涉及到:1、参数个数,2、参数类型,3、返回值类型。

三、交叉类型

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

interface A{a: number};
interface B{b: number};
type AB = A&B;

//使用类型交叉后,类型AB就具有了类型A、B的属性结构
let ab: AB = {
    a:1,
    b:2
}

交叉类型(&)和接口继承(extends)的对比:

​ 相同点:都可以实现对象类型的组合。

​ 不同点:两种方式实现类型组合时,对于同名属性之间,处理类型冲突的方式不同。

interface A{a: number};
interface B{a: string,b: number};
type AB = B&A;
/**
 * 当A、B接口中存在同名属性时,可以使用类型交叉
 * 注意:当同名属性不同类型时,可能会被合并为 never 类型(不能被满足的类型)
 */
// let ab: AB = {
//     a:1,//此时属性a为never类型(不能满足a即为number、又为string),编译报错
//     b:2
// }

// interface C extends A{
//     a: string //直接编译报错,类型冲突
// }

四、泛型

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

泛型函数

/**
 * 创建泛型函数
 *  语法:在函数名称的后面添加 <>(尖括号),尖括号中添加类型变量,比如此处的Type(符合命名规范即可)。
 *  类型变量 Type,是一种特殊类型的变量,它处理类型而不是值。
 *  因为 Type 是类型,因此可以将其作为函数参数和返回值的类型,表示参数和返回值具有相同的类型。
 */
function fun<Type>(param: Type): Type{
    return param;
}

let numResult = fun<number>(10);
let strResult = fun<string>('10');
/**
 * 调用泛型函数时,可以省略 <类型> 来简化泛型函数的调用
 * 充分利用TS的类型参数推断机制,TS根据实际参数类型反推Type类型
 * 说明:当编译器无法推断类型或者推断的类型不准确时,就需要显式地传入类型参数
 */
let booleanResult = fun(true);

/**
 * 为泛型添加约束
 *  通过extends关键字,确保传入的参数类型继承过IAnimal接口,或拥有name属性(参考TS类型兼容性)
 */
interface IAnimal{name: string}
function eat<T extends IAnimal>(animal: T):void{}

/**
 * 泛型变量可以多个
 */
function estimate<T,R>(par1: T,par2: R):void{}

泛型接口

泛型class

你可能感兴趣的:(前端,typescript,javascript,前端)