【Typescript】—TS的基本使用(一)

一、Typescript的基本介绍

TypeScript 是 JavaScript 的一个超集,主要提供了类型系统对 ES6 的支持

优点:

  • 类型系统实际上是最好的文档,大部分的函数看看类型的定义就可以知道如何使用了
  • 可以在编译阶段就发现大部分错误,这总比在运行时候出错好
  • 增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等

二、Typescript命令行安装

npm   install   -g    typescript

以上命令会在全局环境下安装 tsc 命令,安装完成之后,我们就可以在任何地方执行 tsc 命令了。

例如:tsc index.ts

我们约定使用 TypeScript 编写的文件以 .ts 为后缀,用 TypeScript 编写 React 时,以 .tsx 为后缀。

三、Typescript基础

3-1、基本数据类型

布尔值

布尔值是最基础的数据类型,在 TypeScript 中,使用 boolean定义布尔值类型:

let   flag:boolean=true

number类型

使用 number定义数值类型

let  n:number=6

字符串

使用 string定义字符串类型

let  str:string='alley'

空值

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

function  fn():void{}

声明一个 void类型的变量没有什么用,因为你只能将它赋值为 undefinednull

let   unusable: void=undefined;

null&undefined

在 TypeScript 中,可以使用 nullundefined来定义这两个原始数据类型

let  u: undefined=undefined;
let  n: null=null;

void的区别是,undefinednull是所有类型的子类型。也就是说 undefined类型的变量,可以赋值给 number类型的变量:

void类型的变量不能赋值给 number类型的变量

//不会报错
let  num: number=undefined;
let  u: undefined;
let  num: number=u;

//会报错
let  u: void;
let  num: number=u;

3-2、任意值

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

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

let  str:any='alley'
str=123

3-3、联合类型

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

let  age:string|number;
age = 19;
age = '19'

访问联合类型的属性或方法

当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法

//length 不是 string 和 number 的共有属性,所以会报错
function getLength(something: string|number): number{
   r eturnsomething.length;
}
//访问 string 和 number 的共有属性是没问题的
function  getString(something: string|number): string{
   returnsomething.toString();
}

联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:

let  age:string|number;
age='19';
console.log(age.length);//2
age=19;
console.log(age.length);//报错

3-4、接口(Interfaces)

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

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

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

简单列子

//接口一般首字母大写
inteface  Person{
 name:string,
 age:number
}
let  man:Person={
 name:"alley",
 age:19
}

上面的例子中,我们定义了一个接口 Person,接着定义了一个变量 man,它的类型是 Person。这样,我们就约束了 man的形状必须和接口 Person一致

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

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="吴彦祖"//报错

3-5、数组类型

在 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

any 在数组中的应用

一个比较常见的做法是,用 any表示数组中允许出现任意类型:

let  list:any[] =[1,'2',{a:3}]

3-6、函数类型

函数声明

在 JavaScript 中,有两种常见的定义函数的方式——函数声明和函数表达式

// 函数声明(Function Declaration)
function  sum(x, y) {
   returnx+y;
}

// 函数表达式(Function Expression)
let  mySum=function(x, y) {
   returnx+y;
};

一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义较简单

function  sum(x: number, y: number): number{
   returnx+y;
}

注意

输入多余的(或者少于要求的)参数,是不被允许的

function  sum(x: number, y: number): number{
   returnx+y;
}
sum(1, 2, 3);//报错

函数表达式

let  mySum=function(x: number, y: number): number{
   returnx+y;
};

上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 mySum,是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给 mySum添加类型,则应该是这样:

let  mySum: (x: number, y: number) =>number=function(x: number, y: number): number{
   returnx+y;
};

注意不要混淆了 TypeScript 中的 =>和 ES6 中的 =>

在 TypeScript 的类型定义中,=>用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型

可选参数

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

注意:

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

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

参数默认值

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

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

剩余参数

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

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

函数重载

重载允许一个函数接受不同数量或类型的参数时,作出不同的处理

比如,我们需要实现一个函数 reverse,输入数字 123的时候,输出反转的数字 321,输入字符串 'hello'的时候,输出反转的字符串 'olleh'

function  reverse(x: number): number;
function  reverse(x: string): string;
function  reverse(x: number|string): number|string{
 
}

断言

类型断言(Type Assertion)可以用来手动指定一个值的类型。

语法:

<类型>值

值 as 类型

function  fn(age:string|number):number{
     if((<number>age).length){
           return(<string>something).length;
        }
}

3-7、枚举

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

枚举使用 enum关键字来定义

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

enum    status{success, error, wari};

console.log(status['success']);//0
console.log(status['error']);//1
console.log(status['wari']);//2

3-8、类

使用 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);
  }
}

3-9、类与接口

一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements关键字来实现。这个特性大大提高了面向对象的灵活性。

举例来说,门是一个类,防盗门是门的子类。如果防盗门有一个报警器的功能,我们可以简单的给防盗门添加一个报警方法。这时候如果有另一个类,车,也有报警器的功能,就可以考虑把报警器提取出来,作为一个接口,防盗门和车都去实现它:

interface  Info{
 eat()
}


class  Man  implements  Info{
      alert(){}
}

一个类可以实现多个接口

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');
  }
}

接口继承接口

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

interface  Alarm{
   alert();
}

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

3-10、泛型

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

function   createArray<T>(length: number, value: T): Array<T>{
   letresult: T[] =[];
   for(leti=0; i<length; i++) {
       result[i] =value;
  }
   returnresult;
}

createArray<string>(3, 'x'); // ['x', 'x', 'x']

上例中,我们在函数名后添加了 <T>,其中 T用来指代任意输入的类型,在后面的输入 value: T和输出 Array<T>中即可使用了。

接着在调用的时候,可以指定它具体的类型为 string

泛型约束

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

function  loggingIdentity<T>(arg: T): T{
   console.log(arg.length);//会出问题
   returnarg;
}

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

interface  Lengthwise{
   length: number;
}

function   loggingIdentity<TextendsLengthwise>(arg: T): T{
   console.log(arg.length);
   return  arg;
}

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

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

泛型接口

可以使用接口的方式来定义一个函数需要符合的形状

interface   SearchFunc{
(source: string, subString: string): boolean;
}

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

声明:来自IT狗的成长日记,仅代表创作者观点。链接:https://eyangzhen.com/8318.html

IT狗的成长日记的头像IT狗的成长日记

相关推荐

添加微信
添加微信
Ai学习群
返回顶部