上一篇(TypeScript常见的数据类型):http://t.csdn.cn/UjGrn
。
TS中除了上篇文档中描述的常见数据类型之外,还有很多高级数据类型,本文档列举一些常用的类型。
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