TypeScript-基础教程

Posted JackieDYH

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript-基础教程相关的知识,希望对你有一定的参考价值。

一、什么是TypeScript

它是拥有类型系统的javascript的超集,可以编译成纯JavaScript

特点:

  • 类型检查:TS在编译代码时进行严格的静态类型检查

  • 语言扩展:TS会包括来自ES6和未来提案中的特性。比如异步操作和装饰器也会从其他语言中借鉴特性例如接口和抽象类

  • 工具熟悉:TS可以编译成标准的JavaScript可以在任何浏览器和操作系统上运行

从以上特性上来看TS更像是一个工具而不是一门独立的语言

二、TS的安装及使用

cnpm install typescript -S

npx tsc --init 创建tsconfig.json文件

三、数据类型

JS基本数据类型

  • Boolean

  • Number

  • String

  • Undefined

  • Null

  • Array

  • Function

  • Object

  • Symbol

TS数据类型

  • 包含以上9个

  • void

  • any

  • never

  • 元组

  • 枚举

  • 高级类型

1、类型注解

作用:相当于强类型语言中的类型声明

语法:变量/函数:type

基本类型

let bool:boolean = true;
let str:string = "Alley";
let num:number = 18;

数组类型

//数组
let arr1:number[] = [1,2,3,4];
let arr2:Array<number> = [1,2,3,4];

元组类型

元组类型:限定数组的中类型和个数,上述案例中只能有2个数据并且必须是一个数组一个字符串元组类型可以通过push进行添加但是不能访问

//元组
let tuple:[number,string] = [0,'Alley']

对象类型

let obj:x:number = x:1
//定义obj是一个对象并且x值为number

symbol类型

let s1:symbol = Symbol();

undefind null类型

let un:undefined = undefined;
let nu:null = null;

联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种,联合类型使用 |分隔每个类型

let arr2:Array<number | string> = [1,"Alley"];
//数组中的类型可以是数字也可以是字符串

函数类型

let fn = (x:number,y:number):number=>x+y;
//参数x:为数字 y:为数字 返回值也必须是数字

void类型

JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void表示没有任何返回值的函数:

let fn = ()=>
//代表函数的返回值为空

any类型

任意值(Any)用来表示允许赋值为任意类型

如果是一个普通类型,在赋值过程中改变类型是不被允许的,但如果是 any类型,则允许被赋值为任意类型

let x:any;
//any为任意类型

never类型

永远都不会有返回值

let error = ()=>
   throw new Error("error")

2、枚举类型

什么是枚举类型:一组有名字的常量集合。可以理解成手机的通信录Alley=>18399776655

枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。

枚举使用 enum关键字来定义

枚举成员会被赋值为从 0开始递增的数字,同时也会对枚举值到枚举名进行反向映射

枚举类型的优点:

  • 可维护性

  • 可读性

数字枚举

enum Status 
   success,
   error,
   wraning

//数字枚举默认从0开始也就是说Status.success为0 Status.error为1


//同时我们还可以设置初始值,后面的枚举成员依次递增
enum Status 
   success=10,
   error,
   wraning

3、接口

接口的作用 : 可以用来约束对象、函数、类的结构

关键字:interface

在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。

接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。

TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

接口一般首字母大写

interface List 
   id:number;
   name:string;


interface Result 
   data:List[];


function success(result:Result)

let result = 
   data:[
      id:1,name:"Alley",
      id:2,name:"彦祖"
  ]


/*
上述案例中定义了一个List接口,接口中必须存在id和name并且id为number,name为string
同时也定义了一个Result接口,接口中规定key为data value为List接口类型并且是一个数组
还原以上接口的数据为result
*/

定义的变量比接口少了一些属性是不允许的

inteface  Person
    name:string,
    age:number

//会报错 少了age
let man:Person=
       name:"alley"

多一些属性也是不允许的

inteface  Person
    name:string,
    age:number

//会报错 少了age
let man:Person=
      name:"alley",
      age:19,
      sex:"男"

可见,赋值的时候,变量的形状必须和接口的形状保持一致

可选属性

有时我们希望不要完全匹配一个形状,那么可以用可选属性,可选属性的含义是该属性可以不存在 可选属性用?来定义

inteface  Person
    name:string,
    age?:number


let man:Person=
  name:"alley"

只读属性

有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly定义只读属性

inteface  Person
     readonly name:string,
     age?:number


let man:Person=
   name:"alley"

man.name="吴彦祖"//报错

4、数组类型

在 TypeScript 中,数组类型有多种定义方式,比较灵活

「类型 + 方括号」表示法

let  arr:number[] =[1,2,3,4,5]

let  arr:number[] =[1,2,3,'4',5]; //报错

数组泛型

也可以使用数组泛型(Array Generic) Array<elemType>来表示数组:

let  arr=Array<number>=[1,2,3,4,5]

用接口表示数组

interface  NumArray
     [index:number]:number


let  arr:NumArray=[1,2,3,4]

NumArray表示:index的类型是 number,值的类型是 number

5、函数类型

定义函数的方式

let add:(x:number,y:number)=>number;

interface Add
  (x:number,y:number):number


//实现函数
let add:Add = (x,y)=>x+y;

可选参数

与接口中的可选属性类似,我们用 ?表示可选的参数

注意:

可选参数必须接在必需参数后面

function  fn(name:string,age?:number)
      return  name+age;

参数默认值

TypeScript 会将添加了默认值的参数识别为可选参数

function  fn(name:string='alley',age?:number)
      return   name+age;

剩余参数

ES6 中,可以使用 ...rest的方式获取函数中的剩余参数

function  fn(name:string,....rest:any[])

函数重载

如果函数名称相同,但是参数类型不同或者参数个数不同,就需要实现了函数重载

好处:不需要为功能相似的函数起不同的名称

ts实现函数重载:要求定义一系列的函数声明,在类型最宽泛的版本中实现重载

function fn(...rest:number[]):number;



function fn(...rest:string[]):string;



function fn(...rest:any[])
   let first = rest[0];
   if(typeof first == "number")
       //return
  
   
   if(typeof first == "string")
       //return
  

6、类

使用 class定义类,使用 constructor定义构造函数。

通过 new生成新实例的时候,会自动调用构造函数。

使用 extends关键字实现继承,子类中使用 super关键字来调用父类的构造函数和方法。

存储器

使用 getter 和 setter 可以改变属性的赋值和读取行为:

class  Animal
 constructor(name) 
    this.name=name;

 get name() 
    return'alley';

 set name(value) 
    console.log('name: '+value);



let a= new Animal('alley'); // name: alley

a.name='alley'; // name: alley

console.log(a.name); // alley

静态方法

使用 static修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用

class  Person
     static show()


Person.show()

ES7中类的使用

ES6 中实例的属性只能通过构造函数中的 this.xxx来定义,ES7 提案中可以直接在类里面定义

ES7 提案中,可以使用 static定义一个静态属性:

class  Person
    name="alley"
    static  age=19;

public private 和 protected

public修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public

private修饰的属性或方法是私有的,不能在声明它的类的外部访问

protected修饰的属性或方法是受保护的,它和 private类似,区别是它在子类中也是允许被访问的

class Animal
  public  name;
  public  constructor(name) 
      this.name=name;



let  a=new  Animal('Jack');
console.log(a.name); // Jack
a.name='Tom';
console.log(a.name); // Tom


class  Animal
  private  name;
  public  constructor(name) 
      this.name=name;



let  a=new  Animal('Jack');
console.log(a.name); // 会出问题


class  Animal
  private  name;
  public  constructor(name) 
      this.name=name;



class  Cat  extends  Animal
    constructor(name) 
      super(name);
      console.log(this.name);//会出问题
    

如果是用 protected修饰,则允许在子类中访问

class  Animal
  protected  name;
  public  constructor(name) 
      this.name=name;



class Cat extends Animal
    constructor(name) 
      super(name);
      console.log(this.name);
    

抽象类

抽象类 只可以被继承,不可以被实例化

通过关键字abstract进行定义

abstract class Person

let p = new Person();//会报错

7、类与接口

一个接口可以约束类成员有哪些属性以及他们的类型

注意:类实现接口的时候必须实现接口中所有声明的属性

接口只能约束类的公有成员(public)

interface Info
   name:string
   eat()


class Person implements Info
   constructor(name:string)
       this.name = name;
  
   eat()

接口继承接口

接口与接口之间可以是继承关系

interface  Alarm
  alert();


interface  LightableAlarm  extends  Alarm
  lightOn();
  lightOff();

一个类可以实现多个接口

interface  Alarm
  alert();


interface  Light
  lightOn();
  lightOff();


class  Car  implements  Alarm, Light
  alert() 
      console.log('Car alert');

  lightOn() 
      console.log('Car light on');

  lightOff() 
      console.log('Car light off');

8、泛型函数和泛型接口

什么是泛型?

不预先确定的数据类型,具体的类型在使用的时候才能被确定

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性

泛型函数

function fn<T>(value:T):T
   console.log(value);
   return value;


//T类似于any类型,可以保证函数的输入和输出是一致的

//调用
fn<string>("Alley");//在调用的时候来定义类型

泛型接口

interface SearchFunc
   //函数返回值是一个布尔值
(source: string, subString: string): boolean;


let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) 
  return  source.search(subString) !==-1;

泛型类

通过泛型对类进行约束,在实例化的时候来定义这个T的类型那么这个类内部的T都必须是这个类型

class Person<T>
   show(value:T)
       console.log(value);
       return value;
  


let p = new Person<number>()
p.show(1)

泛型约束

在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:

function fn<T>(value:T):T
   console.log(value.length);

  //这里会出问题,原因是并不是所有的参数都有length属性

   return value;

我们可以对泛型进行约束,只允许这个函数传入那些包含 length属性的变量。这就是泛型约束:

interface Len
   length:number


function fn<T extends Len>(value:T):T
   console.log(value.length);
   return value;

上例中,我们使用了 extends约束了泛型 T必须符合接口 Len的形状,也就是必须包含 length属性。

此时如果调用 fn的时候,传入的 value不包含 length,那么在编译阶段就会报错

以上是关于TypeScript-基础教程的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript 官方:JavaScript 中直接支持类型!

TypeScript系列教程06基础类型

TypeScript系列教程06基础类型

TypeScript系列教程03基础语法

TypeScript教程---------基础

TypeScript基础教程