文章目录
- 学习资料
- TypeScript 介绍
- TypeScript 是什么?
- TypeScript 增加了什么?
- TypeScript 开发环境搭建
 
- 基本类型
- 编译选项
- 类
- 声明
- 属性
- 属性修饰符
- getter 与 setter
- 方法
- static 静态方法
- 实例方法
 
- 构造函数
- 继承 与 super
- 抽象类
- 接口
- interface 定义接口
- implements 使用接口
- 多重继承
 
- 泛型
 
学习资料
【尚硅谷TypeScript教程(李立超老师TS新课)】
TypeScript演练场
TypeScript 介绍
TypeScript 是什么?

TypeScript 增加了什么?

TypeScript 开发环境搭建
- 下载Node.js https://nodejs.com.cn/
- 安装Node.js
- 使用npm全局安装typescript- 进入命令行
- 输入:npm i -g typescript
 
- 创建一个ts文件
- 使用tsc对ts文件进行编译- 进入命令行
- 进入ts文件所在目录
- 执行命令:tsc 文件名.ts
 
基本类型
-  类型声明 - 类型的声明是TS非常重要的一个特点
- 通过类型声明可以指定TS中的变量(参数、形参)的类型
- 指定类型后,当为变量赋值时,TS编译器会自动检查是否符合类型声明,符合则赋值,否则报错
- 简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值
- 语法:let 变量: 类型;let 变量: 类型 = 值;function fn(参数:类型, 参数:类型): 类型{... }
 
- 类型的声明是
-  自定类型判断 - TS拥有自动的类型判断机制
- 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
- 所以如果你的变量的声明和赋值是同时进行的,可以省略掉类型声明
 
-  类型 类型 例子 描述 number 1, -33, 2.5 任意数字 string ‘hi’, “hi” 任意字符串 boolean true、false 布尔值true 或 false 字面量 其本身 限制变量的值就是该字面量的值 any * 任意类型 unknown * 类型安全的any void 空(undefined) 没有值(或 undefined) never 没有值 不能是任何值 object {name:‘孙悟空’} 任意的JS对象 array [1,2,3] 任意JS数组 tuple [4,5] 元素,TS新增类型,固定长度数组 enum enum{A,B} 枚举,TS中新增类型 
-  number let decimal: number = 6; let hex: number = 0xf00d; let binary: number = 0b1010; let octal: number = 0o744; let big: bigint = 100n;
-  boolean let isDone: boolean = false;
-  string let color: string = "blue"; color = 'red';let fullName: string = `Bob Bobington`; let age: number = 37; let sentence: string = `Hello, my name is ${fullName}.I ll be ${age +1} years old next month.`
-  字面量 
 也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围let color: 'red' | 'blue' | 'black'; let num: 1 | 2 | 3 | 4 | 5;
-  any let d: any = 4; d = 'hello'; d == true;
-  unknown let notSure: unknown = 4; notSure = 'hello';
-  void let unsable: void = undefined;
-  never function error(message: string): never {throw new Error(message); }
-  object(没啥用) let obj: object = {};
-  array let list: number[] = [1,2,3]; let list: Array<number> = [1,2,3];
-  tuple let x: [string, number]; x = ["hello",10];
-  enum enum Color {Red,Green,Blue } let c: Color = Color.Green;enum Color {Red = 1,Green = 2,Blue = 4 } let c: Color = Color.Green;
-  类型断言 - 有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式: - 第一种let someValue: unknown = "this is a string"; let strLength: number = (someValue as string).length;
- 第二种let someValue: unknown = "this is a string"; let strLength: number = (<string>someValue).length;
 
- 第一种
 
- 有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式: 
编译选项
- 自动编译文件 - 编译文件时,使用-w指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。
- 示例: - tsc xxx.ts -w
 
 
- 编译文件时,使用
- 自动编译整个项目 - 如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。
- 但是能直接使用tsc指令的前提是,要先在项目目录下创建一个ts的配置文件tsconfig.json
- tsconfig.json是一个JSON文件,添加配置文件后(添加配置文件命令,在VSCode终端中输入- tsc -init),只需要- tsc指令即可完成对整个项目的编译。
- 配置选项: - include - 定义希望被编译文件所在的目录
- 默认值:[**/*]
- 示例:
 上述例子中,所有src目录和tests目录下的文件都会被编译"include":["src/**/*","tests/**/*"]
 
- exclude - 定义需要排除在外的目录
- 默认值:["node_modules","bower_components","jspm_packages"]
- 示例:
 上述示例中,src和hello目录下的文件都不会被编译"exclude": ["./src/hello/**/*"]
 
- extends【了解即可】 - 定义被继承的配置文件
- 示例: - "extends": "./configs/base"
 上述示例中,当前配置文件会自动包含config目录下base.json中所有配置信息
 
 
- files【了解即可】 - 指定被编译文件的列表,只需要编译的文件少时才会用到
- 示例:
 列表中的文件都会被TS编译器所编译"files": ["core.ts","sys.ts","types.ts" ]
 
- compilerOptions(重点,以下为compilerOptions的子选项) - 编译器的选项{"compilerOptions": {"target": "ES6","module": "system","outDir": "./dist",// "outFile": "./dist/app.js","allowJs": false,"checkJs": false,"removeComments": false,"noEmit": false,"noEmitOnError": true,"strict": true,"alwaysStrict": true,"noImplicitAny": false,"noImplicitThis": true,"strictNullChecks": true} }
- target - 用来指定ts被编译为的es版本
- 可选项:ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
 
- module
 指定要使用的模块化的规范'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'es2022', 'esnext', 'node16', 'nodenext'.
- lib
 用来指定所需要的库,一般不用动,有默认值可选项:‘es5’, ‘es6’, ‘es2015’, ‘es7’, ‘es2016’, ‘es2017’, ‘es2018’, ‘es2019’, ‘es2020’, ‘es2021’, ‘esnext’, ‘dom’, ‘dom.iterable’, ‘webworker’, ‘webworker.importscripts’, ‘webworker.iterable’, ‘scripthost’, ‘es2015.core’, ‘es2015.collection’, ‘es2015.generator’, ‘es2015.iterable’, ‘es2015.promise’, ‘es2015.proxy’, ‘es2015.reflect’, ‘es2015.symbol’…
- outDir - 用来指定编译后文件所在的目录
 "outDir": "./dist"
- outFile
 将代码合并成一个文件,设置outFile后,所有的全局作用域合并在一个文件中,module中只有’amd’和‘system’支持outFile。"outFile": "./dist/app.js"
- allowJs
 是否对js文件进行编译,默认是false,如果项目中某些模块用js写,可能需要编译"allowJs": false
- checkJs
 检查js是否符合语法规范,默认是false"checkJs": false
- removeComments
 是否移除注释,默认是false"removeComments": true
- noEmit
 不生成编译后的文件,默认是false"noEmit": true
- noEmitOnError
 当有错误时不生成编译后的文件,默认是false"noEmitOnError": false
- strict
 所有严格模式的总开关,默认false(配置后相当于以下配置全都开启)"strict": true
- alwaysStrict
 用来设置编译后的文件是否适用于严格模式,默认是false"alwaysStrict": true
- noImplicitAny
 当某个变量不指定类型时,使用any类型"noImplicitAny": true
- noImplicitThis
 不允许类型不明的 this"noImplicitThis": true
- strictNullChecks
 严格地检查空值,默认false"strictNullChecks": true
 
- 编译器的选项
 
- include 
 
- 如果直接使用
类
声明
用关键字class来声明一个类
class Person{...
}
属性
在TS中类的属性一共有三种,在属性面前添加相应的修饰符便可
class Person{name:string = "zhubajie" // 实例属性static age = 89 // 类属性readonly addr:string = "高老庄" // 只读属性
}
- 实例属性
 直接定义的属性属于实例属性
 他必须通过类实例化之后才能使用
- 类属性
 以static开头的属性为类属性
 他可以通过类直接访问Person.age
- 只读属性
 以readonly定义的属性为只读属性,不可修改
 readonly也可以放再static后面
属性修饰符
pubilc 公共属性,可以再任意位置访问和修改(实例属性,实例化之后访问)
 private 私有属性,只能在类的内部进行访问和修改(一般声明的时候我们会以_开头)
 protected 受保护的属性,只能在当前类和当前类的子类中进行访问
class Person{public name = "SunWuKong"private age = 30protected sex = "male"
}const person = new Person()
console.log(person.name)
console.log(person.age) // 错误 只能在Person这个类中进行访问
console.log(person.sex)  // 错误 只能在Person这个类和其子类中访问
此外,还有readOnly属性,以他修饰的属性只能读取不能修改
getter 与 setter
- 类中的每一个属性内置getter方法和setter方法
 getter方法用于获取属性
 setter方法用于设置属性
- 这样,我们可以对属性读取和操作做一些拦截,设置如下
 当我们进行读取的时候,其实是走的get这个逻辑class Person1{private _name:stringconstructor(name:string){this._name = name;}set name(value:string){this._name = value}get name(){return this._name} }
 当我们对于属性进行赋值的时候,其实是走的set这个逻辑
方法
static 静态方法
经过static关键字修饰的方法属于类方法,可以通过类直接使用
class BaJie{name = "BaJie"static age = 18static sayName(){console.log("八戒")}
}// 通过类直接访问
BaJie.sayName()
console.log(BaJie.age);const bajie = new BaJie()
bajie.sayName() // 实例化之后不可访问
当有不规范的语法的时候,ts就不会进行编译,如上面的编译如下
var BaJie = /** @class */ (function () {function BaJie() {this.name = "BaJie";}BaJie.sayName = function () {console.log("八戒");};BaJie.age = 18;return BaJie;
}());
// 通过类直接访问
BaJie.sayName();
console.log(BaJie.age);
实例方法
在类中直接定义的方法为实例方法,没有任何关键字的修饰
这种方法只能在类实例化之后进行使用
class BaJie{name = "BaJie"age = 18sayName(){console.log("八戒")}
}// 通过类直接访问
BaJie.sayName() // 错误的访问方法
console.log(BaJie.age); // 错误的访问方法
// 同样,实例化之后也是可以访问的
const bajie = new BaJie()
bajie.sayName() 
console.log(bajie.name);
构造函数
class Person{name:string;age:nubmer;constructor(name:string,age:number){this.name = namethis.age = age}
}const p1 = new Person('张三',18);
const p2 = new Person('李四',20);console.log(p1);
console.log(p2);
constructor被称为构造函数
 构造函数会在对象创建时调用
继承 与 super
// 父类
class Animal{name:string;age: number;constructor(name:string,age:number){this.name = name;this.age = age}sayName(){console.log(this.name)}
}
// 子类
class Dog extends Animal{run(){console.log(`${this.name}run`);}
}
class Cat extends Animal{sayName(){console.log(`我是${this.name}`);}
}
const dog = new Dog("旺财",19)
const cat = new Cat("汤姆",20)
dog.sayName()
dog.run()
cat.sayName()
可以将代码复制到 TypeScript演练场 运行

 我们使用extends关键字来进行继承,其中被继承的Animal为父类,Dog为子类
 继承之后,子类会拥有父类的一切属性和方法
 子类也可以自己定义一些方法,如上面例子中的run
 子类也可以写与父类相同的方法,这样执行方法的时候会执行子类的方法,叫做方法重写(Cat类中重写了sayName方法)
抽象类
abstract class Animal{name:string;constructor(name:string){this.name = name;}abstract sayName():void;
}class Dog extends Animal{age:number;constructor(name:string,age:number){super(name);this.age = age;}sayName(): void {console.log(`我是${this.name},我今年${this.age}岁了`);}
}const dog = new Dog("旺财",23)
dog.sayName() // 我是旺财,我今年23岁了用abstract关键字来定义抽象类和抽象方法
- 抽象类
 抽象类不能用来创建对象
 抽象类只能用于继承(说明类中有哪些属性,哪些方法)
 在抽象类中可以添加抽象方法(如sayName方法)
- 抽象方法
 抽象方法没有方法体(如sayName方法),且只能定义在抽象类中
 子类必须对于抽象类中的抽象方法进行复写
接口
接口用于描述一个类或者一个对象的结构,描述他们的属性和方法,所以接口可以当做一个类的声明
interface 定义接口
我们使用interface来定义一个接口,定义的方法全部为抽象方法,必须重写
接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
同时接口也可以当成类型声明去使用
interface myInterface{name:string,age:number,sex:"male"|"female",sayName():void
}
implements 使用接口
一般我们使用implements关键字来使用接口
class Person implements myInterface{name: string;age: number;sex: "male" | "female";sayName(): void {console.log(this.name);}
}
多重继承
使用extends来进行接口的继承,且后可以跟多个接口,实现多重继承
interface Obj {[propName:string]:any
}interface myInterface{name:string,age:number
}interface IPerson extends myInterface,Obj{sex:"male"|"female",sayName():void
}class Person implements IPerson{name: string;age: number;sex: "male" | "female";hobby:"read"|"write"sayName(): void {console.log(this.name);}
}
泛型
在指定函数或者类的时候,如果遇到类型不明确的话,就可以使用泛型(不先指定类型,使用的时候进行类型的转换)
一般在声明的变量后面加一个尖括号来声明泛型
 
 当我们进行类型转换后,编辑器就会有相应的提示
当然我们也可以不指定泛型,ts会进行自动的类型转换
- 指定多个泛型function fn1<T,K>(a:T,b:K):K{console.log(a);return b }fn1<number,string>(1,'hello')
- 定义类class Person3<T>{name:Tconstructor(name:T){this.name = name} }const person4 = new Person3<string>("Jack") console.log(person.name);
- 泛型与接口
 泛型也可以继承接口,使用extends关键字,他表示泛型必须满足接口的条件interface IPerson1{name:string,age:number }function fn2<T extends NameInterface>(a:T):string{return a.name }fn2<IPerson1>({name:"小敏",age:10})