一、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类型的变量没有什么用,因为你只能将它赋值为undefined和null:
let unusable: void=undefined;
null&undefined
在 TypeScript 中,可以使用
null和undefined来定义这两个原始数据类型
let u: undefined=undefined;
let n: null=null;
与
void的区别是,undefined和null是所有类型的子类型。也就是说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