1.TypeScript简介及入门案例

【前端】TypeScript核心知识点讲解-LMLPHP

(1)什么是TypeScript?

TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 (ES6)标准。

TypeScript 由微软开发的自由和开源的编程语言。

TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。

(2)JavaScript 与 TypeScript 的区别

TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改。

TypeScript 通过类型注解提供编译时的静态类型检查。

TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。

(3)TypeScript环境搭建

  • 安装node.js
地址: https://nodejs.org/en/download/
  • 检查安装情况
node -v
  • npm配置国内镜像源
npm config set registry https://registry.npm.taobao.org

配置之后可以验证是否成功:
npm config get registry
  • 使⽤npm全局安装typescript
npm i -g typescript
  • 验证
tsc -v
Version 5.2.2

(4)编写第一个TS程序

  • 创建demo.ts
console.log('李祥');
  • 编译成js文件
tsc demo.ts
  • html引入js文件

【前端】TypeScript核心知识点讲解-LMLPHP

2.TypeScript基础数据类型

(1)TS中的类型声明

类型声明是TS中⾮常重要的特点。

通过类型声明可以指定TS中变量(形参)的类型。

指定类型后,当变量赋值时,TS编译器就会⾃动检查值是否符合声明类型,如果符合就赋值,不符合就报错。

简单的说,类型声明就是给变量设置了类型。使得变量只能存储某种类型的值。

  • 语法:
let 变量名:类型;//只声明,未赋值
let 变量名:类型=;//声明并赋值 
function fun(参数:类型,参数:类型):类型{}
  • TS的基础数据类型

    • number类型:双精度64位浮点值。它可以用来表示整数和分数。

    • boolean类型:表示逻辑值:true和false

    • string类型:一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式

(2)TS自动类型判断

  • 什么是⾃动类型判断
TS拥有⾃动类型判断机制。
当对变量的声明和赋值同时进⾏时,TS编译器会⾃动判断变量类型。
所以如果你的变量的声明和赋值是同时进⾏的,可以省略掉类型声明。
  • 案例
//声明一个变量未赋值
let num:number;

num = 7;

//声明一个变量进行赋值
let sum = 9;

console.log(typeof num);
console.log(typeof sum);
  • 控制台打印:
number
number
  • 如果强行将sum赋值string类型 会编译报错

【前端】TypeScript核心知识点讲解-LMLPHP

(3)TS字面量声明

  • 什么是字面量
客观存在⽆法改变的值。
  • 字面量声明
//使⽤字⾯量声明后a的值,永远是23 相当于常量不能修改
let a:23;
//如果修改ts就会提醒
const a=23;

【前端】TypeScript核心知识点讲解-LMLPHP

(4)TS中的any类型

any表示任意数据类型,⼀个变量设置类型为any后相当于对该变量关闭了TS的类型检测。

//显式的any类型声明
let a:any;
a=12;
a=true;
a="lixiang";

//隐私的any类型声明,声明如果不指定类型,则TS解析器会⾃动判断变量的类型为any
let b;
b=23;
b=false;
b="lixiang";

使用any类型的变量可以被赋值为任何类型的值,而不会导致编译器报错或警告。使用any类型时需要注意,因为它是一个非常灵活的类型,可能会导致类型不一致或意外的行为。

(5)TS中unknown类型

unknown是TypeScript中比较特殊的一种类型,它用于描述类型不确定的变量。这与any类型相似,但更安全,因为对未知值做任何事情都是不合法的。

unknown:表示未知类型的值;
let b:unknown;
b=123;
b=true;
b='lixiang';

let c:unknown;
c='123';
let d:string;

d=c;
//此时TS解析器提示是报错的
//虽然 变量中的字⾯量都是string,但是 d是string类型c是unknown所以不能赋值
//假如我就想让c的值赋值给d,应该这样操作
if(typeof c ==='string'){
 d=c;//这样就可以完成赋值了
}

(6)TS中的类型断⾔

类型断⾔:可以⽤来告诉TS解析器变量的实际类型

语法:

  • 变量 as 类型;
  • <string> 变量;
利⽤类型断⾔来处理上⼀节的unknown赋值的⼩问题
let c:string;
let d:unknown;
d="lixiang";
c=d as 'string';
console.log(typeof c);
输出结果:string

3.TypeScript的函数声明

(1)对函数中形参进⾏类型声明

与JavaScript不同的是TypeScript函数声明中增加了对形参类型的声明

function fun(num1:number,num2:number):number{
 	 return num1+num2;
}

这样声明的函数,参数只能传递两个数值类型的值,返回也是一个数值类型的值。

所以传入一个参数,或者传入的参数不是数字的编译器都会报错。

//传递不是number的实参
fun('li','xiang');

//多参数
fun(123,4556,55,56);

//少参数
fun(11);

(2)函数中返回值类型的声明

  • 不设置返回值类型,但是有返回值
function fun(){
 	return true;
}

//这个时候TS解析器会根据返回值的类型进⾏判断,返回值类型是什么函数返回值类型就是什么
let result=fun();
console.log(typeof result);
打印结果:boolean
  • 设置返回值类型为void
//void:⽤来表示空,以函数为例,就表示没有返回值的函数
function fun():void{
 	return;
}
  • 设置返回值类型为 never
//never:永远不会返回结果
function fun():never{
 	throw new Error("异常");
}

【前端】TypeScript核心知识点讲解-LMLPHP

4.TypeScript复杂数据类型

(1)对象类型声明

let a:object; //声明一个object对象类型的数据
let b:{name:string};//声明一个对象b,里面有个string类型的name属性
//给b变量赋值
b={name:'lixiang'}
  • 语法:
{属性名1:属性值1,属性名2:属性值2}
当我们采用这种方式指定对象的时候,必须要求格式一摸一样。
  • 指定的对象它必须包含⼀个name,但是还有age和sex这个俩个变量是可能有可能有没有的,这种情况我们该怎样做?
let b:{name:string,age?:number,sex?:string}; // 在属性后面加个?表示这个属性非必需
b={name:'lixiang'};
b={name:'zhangsan',age:18};
  • 当我们只知道我们必须有的属性,⽽其他的不必须我们不知道,该怎么处理?
let b:{name:string,[propName:string]:unknown};
//这就表示我们指定b中存储的类型是对象,并且这个对象必须含有⼀个name的属性,类型为string,这个对象还可以有其他可选属性,只要属性名满⾜是字符串,属性值是unknown即可
[propName:string]:这个任意命名,就表示属性的名字,这个属性名字的类型是string。js中属性名⼀般都是⽤string定义。
[propName:string]:unknown;合起来就代表属性名为string类型,为可选的并且这个属性的值为unknown类型。

(2)数组类型声明

第一种:let 变量名:类型名[];
第二种:let 变量名:Array<类型名>;
let e:string[]; //声明一个字符串类型的数组,表示e中只能存储字符串
let d:number[]; //声明一个数字类型的数组
let f:boolean[]//声明一个boolean类型的数组
let e:Array<number>; //另一种方式声明数值类型的数组
let e:Array<any>; //声明一个存储任意类型的数组
let e:any[]; //声明一个存储人意类型的数组

(3)元组类型声明

元组(tuple)就是定⻓的数组。且类型自定义,类型相互对应。

let h:[string,string];//定义元组存储两个值,第⼀个值是string类型。第⼆个值也是string
//定义的时候多⼀个少⼀个也不⾏,必须按照声明的结构定义数组,不然TS解析器就会提示报错
h=['li','xiang'];

let s:[string,number]//定义元组存储两个值,第⼀个值是string类型。第⼆个值是number
s=['s',1];
元组书写语法:[类型,类型,类型];

(4)枚举类型声明

枚举(Enum),可以定义⼀些带名字的常量。⽤于清晰地表达意图或创建⼀组有区别的⽤例。

  • 语法:
enum 枚举名称{成员1,成员2....};
  • 数字枚举:
// 默认情况下,第⼀个枚举值是0,后续⾄依次增1
enum Color
{
 red,
 blue,
 yellow
}
alert(Color.blue);
  • 字符串枚举
enum Gender {
 male = '1',
 female = '0',
}
alert(Gender.male);

(5)联合类型声明

在ts中我们可以使⽤ "|" 进⾏联合类型声明
语法:let 变量名:声明类型1|声明类型2.....;
//就表示声明⼀个变量名,它可以是类型1还可以是类型2或者更多

let sex = string:number;
sex = 1;
sex='1'
//这两种赋值方式都可以

(6)类型别名

  • 声明一个类型别名:type t = ‘’;

  • 声明一个a的类型变量:type a = 1|2|3|4|5|;

  • 这时我们声明一个b变量:let b = a; b就等价于let b = 1|2|3|4|5|;

5.TypeScript中的配置

(1)⾃动编译⽂件

  • ⾃动编译单个⽂件
编译⽂件时,使⽤-w指令后,TS编译器会⾃动监视⽂件的变化,并在⽂件发⽣改变时对⽂件进⾏重新编译。
tsc ⽂件名.ts -w
  • ⾃动编译当前项⽬下的所有的ts⽂件
如果直接使⽤tsc指令,则可以⾃动将当前项⽬下的所有的ts⽂件编译成js⽂件。
要在项⽬的根⽬录下创建⼀个ts的配置⽂件 tsconfig.json。tsconfig.json是⼀个json⽂件,添加配置后,只需要tsc命令即可完成对整个项⽬的编译。

(2)tsconfig.json中的配置项讲解

  • include:定义希望被编译⽂件所有的⽬录
默认值:[**/**]
案例:"include":["dev/**/*","prop/**/*"] 
**:表示任意⽬录
*:表示任意⽂件
就代表所有的dev⽬录和prop⽬录下的⽂件都会被编译
  • exclude:定义不需要编译的⽬录
默认值:["node_modules","bower_components","jspm_packages"]
案例:"exclude":["./prop/**/*"]
代表不编译prop⽬录下的所有⽂件
  • extends:定义被继承的配置⽂件
案例:"extends":"./config/base"
表示当前配置⽂件会⾃动包含config⽬录下base.json中的所有配置信息
  • files:指定需要编译⽂件的列表
案例:
 "files":
 [
 "one.ts",
 "two.ts",
 "three.ts",
 "four.ts"
 ]
表示列表中⽂件都会被TS编译器编译
  • complierOptions:ts编译时的配置
target:指定ts编译的js⽬标版本
可选值:"ES3"(默认), "ES5""ES6"/ "ES2015""ES2016""ES2017""ESNext"。
案例:"compilerOptions":{"target":"ES6"}
表示我们所编写的ts代码将会被编译ES6版本的js代码
module:指定使⽤的模块化规范
可选值:"None""CommonJS""AMD""System""UMD""ES6""ES2015"。
只有 "AMD""System"能和 --outFile⼀起使⽤。
"ES6""ES2015"可使⽤在⽬标输出为 "ES5"或更低的情况下。
lib:指定编译过程中需要引⼊的库⽂件的列表
可选值:"ES5""ES6""ES2015""ES7""ES2016""ES2017""ES2018""ESNext""DOM""DOM.Iterable""WebWorker""ScriptHost""ES2015.Core""ES2015.Collection""ES2015.Generator""ES2015.Iterable""ES2015.Promise""ES2015.Proxy""ES2015.Reflect""ES2015.Symbol""ES2015.Symbol.WellKnown""ES2016.Array.Include""ES2017.object""ES2017.Intl""ES2017.SharedMemory""ES2017.String""ES2017.TypedArrays""ES2018.Intl""ES2018.Promise""ES2018.RegExp""ESNext.AsyncIterable""ESNext.Array""ESNext.Intl""ESNext.Symbol"
案例:
 "compilerOptions":{
 "target":"ES6",
 "lib":["ES6","DOM"]
 }
注意:如果--lib没有指定默认注⼊的库的列表。默认注⼊的库为:
针对于--target ES5:DOM,ES5,ScriptHost
针对于--target ES6:DOM,ES6,DOM.Iterable,ScriptHost
outDir:⽤来指定编译后⽂件所在的⽬录
案例:
 "compilerOptions":{
 "target":"ES6",
 "lib":["ES6","DOM"],
 "outDir":'./dist'
 }
outFile:将编译的代码合并成⼀个⽂件
案例:
 "compilerOptions":{
 "target":"ES6",
 "lib":["ES6","DOM"],
 "outDir":'./dist',
 "outFile":'./dist/main.js'
 }
"outFile":'./dist/main.js'
就表示把编译后的⽂件合并的main.js这⽂件中,最后只会输出⼀个js⽂件
mudule只能使⽤ amd或者是system
其实outFile这个功能我们在⼯作中也很少使⽤,因为我们打包的时候都是通过打包⼯具进⾏使⽤的。
allowJs:是否对js⽂件进⾏编译
默认值:false
案例:"allowJs":true
checkJs:是否检查js代码符合语法规范
默认值:false
案例:"checkJs":true
removeComments:在编译的时候是否移除注释
默认值:false
noEmit:不⽣成编译后的⽂件
默认值为:false
案例:"noEmit":true
noEmitOnError:当存在语法错误的时不⽣成编译后的⽂件
默认值:false
案例:"noEmitOnError":true
alwaysStrict:js中有⼀种模式叫做严格默认,它语法更严格,在浏览器执⾏的性能更⾼,开发时候我们都会让我们的代码在严格模式下执⾏。
如果是在js⽂件的话 只需要在js⽂件的开头加⼊⼀个字符串。
"use strict";
设置编译后的⽂件是否使⽤严格模式
默认值:false
案例:"alwaysStrict":true
noImplicitAny:不允许隐式的any类型
默认值为:false
案例:"noImplicitAny":true
strictNullChecks:严格的检查空值
默认值为:false
案例:"strictNullChecks":false
strict:所有严格检查的总开关
默认值为:false
案例:"strict":false

6.TypeScript语法进阶

(1)直接运⾏ts⽂件

  • ⾸先全局安装ts-node
npm install -g ts-node
  • 执⾏ts-node命令即可
ts-node hello.ts
运行结果:hello lixiang

(2)TypeScript中的类

  • 如何定义类
//通过class这个关键字来定义⼀个类
class Person{
 name:string;
 age:number;
}
//通过这个类实例化⼀个对象
let person=new Person;
如果不传递参数的话()可以省略
  • 静态修饰符(static)
static修饰的属性或者是⽅法,属于类的。可以通过类名调⽤,不属于实例的,实例没办使⽤
class Person {
  static name: string = "lixiang";
  static sayHello() {
    console.log("你好!");
  }
}
Person.sayHello();
使⽤⽅法:放在属性名或者⽅法名前⾯
  • readonly只读
被readonly修饰的属性,只能读取不能修改
案例:Person.full_name='lixiang'

【前端】TypeScript核心知识点讲解-LMLPHP

(3)类中的构造⽅法

  • 如何在类中定义⼀个构造⽅法
class Dog{
 constructor(){
 		console.log("我创建⼀个Dog");
 }
}
const dog=new Dog();
//当我们调 new Dog();的时候我们就等于调⽤Dog中的构造⽅法
//在实例犯法中,this就表示当前的实例
//在构造⽅法中当前对象及时当前新建的那个对象
//可以通过this向新建的对象中添加属性
  • 定义⼀个有参构造⽅法
class Dog {
  constructor(name: string) {
    console.log(name);
  }
}
const dog = new Dog("黑妞");
//创建的时候必须传递⼀个string类型的参数
  • this改造构造⽅法
class Dog {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

(4)TS中的继承

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(this.name + "吃东西");
  }
}
class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
}
此时,Animal被称为⽗类,Dog被称为⼦类,使⽤继承后,⼦类将会拥有⽗类所有的⽅法和属性。
通过继承可以将多个类中共有的代码写在⼀个⽗类中。
这样只需要写⼀次即可让所有⼦类都同时拥有⽗类中的属性和⽅法。
如果希望在⼦类中添加⼀些⽗类中没⼜的属性或⽅法直接加就⾏。

(5)TS中的重写

重写父类的方法,子类中会覆盖掉父类的方法


class Animal{
    name:string="动物";
    sleep(){
        console.log("动物在睡觉");
    }
}

class Dog extends Animal{
    name:string="狗";
    sleep(){
        console.log("狗在睡觉");
    }
}

let jm=new Dog();
console.log(jm.name);
jm.sleep();
运行结果:
狗在睡觉
狗

(6)super关键字

1:在当前类中 super就表示当前类的父类

2:如果在子类中写了构造方法,在子类构造方法中必须对父类的构造方法进行调用

子类不写构造方法,父类将自动调用,如果子类写构造方法,则会把父类构造方法覆盖调用,所有必须调用父类的构造方法

super();//有参数也需要传递对应的参数,不然会TS解析器会提示报错
class Animal{
    name:string;
    sleep(){
        console.log(this.name+"在睡觉");
    }
    constructor(name:string){
        this.name=name;
    }
}

class Dog extends Animal{
    age:number;
    sleep(){
        //super   代表父类   父类 -》超类
        super.sleep();
    }
    constructor(name:string,age:number){
        super(name);
        this.age=age;
    }
}

let jm=new Dog("金毛",12);
jm.sleep();
运行结果:
金毛在睡觉

(7)TS中的抽象类

  • 抽象类
以abstract开头的类被称为抽象类,抽象类和其他类区别不大,只是不能用来创建对象。抽象类就是专门用来被继承的类。
  • 抽象方法
抽象类中可以添加抽象方法
抽象方法使用abstract开头,没有方法体
抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
abstract syaHello():void;
abstract class Animal{
    name:string="抽象类";
    abstract sleep():void;
}

class JM extends Dog{
    sleep(){
       console.log("狗在睡觉");
    }
}
let jm = new JM();
jm.sleep();
运行结果:
狗在睡觉

(8)TS中的接口

  • 接口
接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法。同时接口也可以当成类型声明去使用。接口可以重复声明,取所有相同接口名的并集
  • 语法
通过 interface 关键字来定义
//interface
interface myInterface{
    name:string;
    sleep():void;
}
interface myInterface{
    age:number;
}
class Person implements myInterface{
    name:string;
    age:number;
    gender:string;
    sleep(){
        console.log(this.name+"睡觉");
    }
    constructor(name:string,age:number,gender){
        this.name=name;
        this.age=age;
        this.gender=gender;
    }
}

let c=new Person('lixiang',19,'男');
c.sleep();
运行结果:
lixiang睡觉

(9)TS中属性的封装

  • 属性修饰符
public:修饰的属性可以在任意位置访问,是默认值
private: 私有属性,私有属性只能在类内部进行访问,通过在类中添加方法使得私有属性可以被外部访问
protected: 受保护的属性,只能在当前类何当前类的之类中访问
  • 属性封装
class Person {
    private name:string;
    private age:number;
    constructor(name:string,age:number){
        this.name=name;
        this.age=age;
    }
}
  • 属性存取器
getter 方法用来读取属性
setter 方法用来设置属性

class Person {
    private name:string;
    private age:number;
    constructor(name:string,age:number){
        this.name=name;
        this.age=age;
    }
    get name():string{
        return this.name;
    }
    set name(name:string):void{
        this.name=name;
    }
}
let obj =new Person("lixiang",18);
obj.setAge=12;
console.log(obj.getAge);
运行结果:
12

(10)TS中的泛型

  • 泛型的使用场景
在定义函数或类时,如果遇到类型不明确就可以使用泛型
泛型就是一个不确定的类型
  • 使用简单的泛型
function cache<泛型名>(value:泛型名):泛型名{
    return 泛型名;
}
  • 泛型的约束
我们可以指定泛型的类型,如果我们不指定TS解析器会根据我们传递的参数进行类型推测(建议我们在使用泛型的时候指定泛型的类型)
使用方法:
cache<指定泛型类型>('lixiang');
  • 创建多个泛型
function cache<泛型名1,泛型名2>(value1:泛型名1,value2:泛型名2):T{
    return T;
}

cache<泛型类型1,泛型类型2>(实参1,实参2);
  • 泛型在接口中的使用
interface Animal<T>{
    name:T;
}

class Dog<T,F>  implements Animal<T>{
    name:T;
    age:F;
    constructor(name:T,age:F){
        this.name=name;
        this.age=age;
    }
}
let jm=new Dog<string,number>("黑妞",12);
console.log(jm.name);
console.log(jm.age);
运行结果:
黑妞
12

记得给博主三连哦!!!
【前端】TypeScript核心知识点讲解-LMLPHP

11-11 05:24