TypeScript的入门教程
TypeScript的入门教程
什么是TypeScript
- TypeScript是以JavaScript为基础构建的语言
- 它扩展了JavaScript,并添加了类型
- 是JavaScript的一个超集
- TypeScript可以在任务支持JavaScript的平台上运行。
- TS不能被S解析器直接执行,需要编译成JS
TypeScript增加了什么?
- 类型
- 支持ES的新特性
- 强大的开发工具
- 添加ES不具备的新特性
- 丰富的配置选项
TypeScript开发环境搭建
- 下载Node.js
64位: https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64.msi。
32位: https://nodejs.org/dist/v14.15.1/node-v14.15.1-x86.msi - 安装Node.js
- 使用npm全局安装typescript
- 进入命令行
- 输入: npm i -g typescript
- 创建一个ts文件
- 使用tsc对ts文件进行编译
- 进入命令行
- 进入ts文件所在目录。
- 执行命令:tsc xxx.ts
基本类型
-
类型声明
- 类型声明是TS非常重要的一个特点
- 通过类型声明可以指定TS中变量(参数、形参)的类型
- 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错。简而言之,类型声明给变是设置了类型,使得变量只能存储某种类型的值
- 语法:
let变量:类型; let变量:类型=值; function fn(参数:类型,参数:类型):返回类型{ }
-
自动类型判断
- TS拥有自动的类型判断机制
- 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型。所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明
-
类型
类型 例子 描述 number 1,-33,2.5 任意数字 string ‘hi’ , “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 decima7: number = 6; let hex: number = Oxf00d; let binary: number = 0b1010; let octa1: number = 0o744; let big: bigint = 100n;
-
boolean
let isDone: boolean = false;
-
string
let color : string = "blue"; color = 'red ' ; let fullName: string = `Bob Bobbington`; 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 = 'he1lo';
-
void
let unusable: void = undefined;
-
never
function error (message: string): never { throw new Error (message); }
-
object(没啥用)
let obj: object = 0;
-
array
let list: number[] = [1,2,3]; let list: Array<number> = [1,2,3];
-
tuple
let x: [string,number]; x = ["hello",10];
-
enum
enum Sex { male = 0, female = 1 } let obj6: { name: string, sex: Sex } obj6 = { name: "freedom", sex: Sex.female }
-
编译选项
自动编译文件
编译文件时,使用-w指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。示例:
tsc Xxx.ts -w
自动编译整个项目
- 如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。
- 但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件tsconfig.json
- tsconfig.json是一个JSON文件,添加配置文件后,只需只需tsc命令即可完成对整个项目的编译。配置选项:
-
include
- 定义希望被编译文件所在的目录
- 默认值:["**/*""]
- 示例:
上述示例中,所有src目录和tests目录下的文件都会被编译。"include" : ["src/**/*","tests/**/*"]
**
表示任意目录,*
表示任意文件
-
exclude
- 定义需要排除在外的目录
- 默认值:[“node_modules”, “bower_components” , “jspm_packages”]
- 示例:
上述示例中,src 下hello目录下的文件都不会被编译"exclude": ["./src/hello/**/*"]
-
extends
- 定义被继承的配置文件
- 示例:
上述示例中,当前配置文件中会自动包含config目录下base.json中的所有配置信息"extends" : "./ configs/base"
-
files
- 指定被编译文件的列表,只有需要编译的文件少时才会用到
- 示例:
列表中的文件都会被TS编译器所编译"files" : [ "core.ts" , "sys.ts ", "types.ts ", "scanner.ts", "parser.ts", "utilities.ts", "binder.ts ", "checker.ts", "tsc.ts" ]
-
compilerOptions
- 编译选项是配置文件中非常重要也比较复杂的配置选项
- 在compilerOptions中包含多个子选项,用来完成对编译的配置
- 项目选项
- target
-
设置ts代码编译的JS目标版本
-
可选值:
- ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
-
示例:
"compilerOptions " : { "target" : "ES6" }
如上设置,我们所编写的ts代码将会被编译为ES6版本的js代码
-
- lib
- 指定代码运行时所包含的库(宿主环境).
- 可选值:
- ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、webWorker、ScriptHost …
- module
- 指定要使用的模块化的方案
- 可选值:“None”、“CommonJS”、“AMD”、“System”、“UMD”、“ES6”、“ES2015”、“ES2020”或“ESNext”。
- outDir
- 用于指定编译的输出目录
- allowJs
- 是否允许编译JavaScript代码,默认为false
- checkJs
- 是否检查JavaScript的代码是否符合语法规范,默认是false
- removeComments
- 输出结果是否移除注释
- alwaysStrict
- 始终开启严格模式
- noImplicitAny
- 不允许隐式的any类型,建议设置为true
- noImplicitThis
- 不允许隐式的this,建议设置为true
- strictNullChecks
- 启用严格的null检查,建议开启此配置。
- strict
- 启用所有的严格检查
- target
- 项目选项
-
结合Webpack进行使用
-
创建一个空白文件夹,并进入到这个空白文件夹,执行npm的初始化操作。
npm init -y
命令用于在当前文件夹下创建一个package.json文件,这个文件是包管理的配置文件。mkdir ts-study-webpack cd ts-study-webpack npm init -y
-
安装所需要的依赖。
npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin html-webpack-plugin @babel/core @babel/preset-env babel-loader core-js
-
编写webpack的配置文件。在目录下创建一个配置文件webpack.config.js文件,并设置内容如下所示:
const path = require('path'); // 引入html插件 const HTMLWebpackPlugin = require('html-webpack-plugin'); // 引入clean插件 const {CleanWebpackPlugin} = require('clean-webpack-plugin'); // webpack中的所有的配置信息都应该写在module.exports中 module.exports = { // 指定入口文件 entry: "./src/index.ts", // 指定打包文件所在目录 output: { // 指定打包文件的目录 path: path.resolve(__dirname, 'dist'), // 打包后文件的文件 filename: "bundle.js", // 告诉webpack不使用箭头 // 默认打包后是一个立即执行的箭头函数,在IE 11中也是无法执行的! // 加上下面的配置,可以在webpack打包时,最外层不再是箭头函数 // webpack新版本已经不想兼容IE了!233 environment: { arrowFunction: false } }, // 指定webpack打包时要使用模块 module: { // 指定要加载的规则 rules: [ { // test指定的是规则生效的文件 test: /\.ts$/, // 要使用的loader // Webpack在加载时是"从后向前"加载! use: [ // 配置babel { // 指定加载器 loader: "babel-loader", // 设置babel options: { // 设置预定义的环境 presets: [ [ // 指定环境的插件 "@babel/preset-env", // 配置信息 { // 要兼容的目标浏览器 targets: { "chrome": "58", "ie": "11" }, // 指定corejs的版本 // package.json中的版本为3.8.1 "corejs": "3", // 使用corejs的方式,"usage" 表示按需加载 "useBuiltIns": "usage" } ] ] } }, 'ts-loader', ], // 要排除的文件 exclude: /node-modules/ } ] }, // 配置Webpack插件 plugins: [ new CleanWebpackPlugin(), new HTMLWebpackPlugin({ // title: "这是一个自定义的title" template: "./src/index.html" }), ], // 用来设置引用模块 resolve: { extensions: ['.ts', '.js'] } }
-
创建ts的配置文件,创建一个文件为tsconfig.json,并设置内容如下:
{ "compilerOptions": { "strict": true, "target": "ES6", "module": "ES6" } }
-
在package.json文件中修改部分代码,最后的代码如下所示:
{ "name": "ts-study-webpack", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack", "start": "webpack serve --open chrome.exe" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "cnpm": "^6.2.0" }, "devDependencies": { "@babel/core": "^7.14.3", "@babel/preset-env": "^7.14.4", "babel-loader": "^8.2.2", "clean-webpack-plugin": "^4.0.0-alpha.0", "core-js": "^3.13.1", "html-webpack-plugin": "^5.3.1", "ts-loader": "^9.2.2", "typescript": "^4.3.2", "webpack": "^5.38.1", "webpack-cli": "^4.7.0", "webpack-dev-server": "^3.11.2" } }
-
在命令行中运行命令
npm run start 或 npm run build
面向对象
类
使用class关键字创建一个类。类里可以定义类的属性跟方法。如下面代码所示,height属性是一个实例变量,若使用关键字statis修饰,例如age,就变成了静态属性,若使用readonly定义,则变成了只读变量。这一点跟面向对象的语言Java类似,readonly则类似于final,static在Java中也是static。
// 使用class关键字定义一个类
class Person {
heigth = 170
// 使用readonly表示只读
readonly name: String = "freedom"
// 使用static描述的是静态属性
static age = 20;
// 定义一个实例方法
sayHello(){
console.log("Hello");
}
// 定义一个静态方法
static sleep(){
console.log("Sleep")
}
}
var person = new Person();
console.log(person.name);
console.log(Person.age);
person.sayHello()
Person.sleep()
构造函数
首先看下面的代码
class Dog{
name:string;
constructor(name:string) {
this.name = name;
}
}
var dog = new Dog("旺财");
var dog1 = new Dog("小黄");
构造函数就是创建对象的时候会执行的方法,我们可以在构造函数中做一些赋值、检验等工作。TS中类的构造函数名字为constructor
。在类中,可以使用this
关键字调用当前对象。
继承
TS中类的继承使用关键字extends,这个跟Java中一样。如下代码所示:
class Animal {
name:string;
constructor(name: string) {
this.name = name;
}
sayHello(){
console.log(this.name + "~~~")
}
}
class Cat extends Animal{
age:number;
constructor(name:string, age: number) {
super(name);
this.age = age
}
sayHello() {
super.sayHello();
console.log("喵喵喵")
}
}
var cat = new Cat("小花", 2);
cat.sayHello()
我们先定义了一个Animal类表示动物,这个类包含了属性name和一个sayHello的方法。然后我们又定义了一个类Cat表示猫。我们知道猫也属于动物的一种。所以我们让Cat这个类继承了类Animal。这时Animal类是Cat的父类,而Cat是Animal类的子类。
在构造函数或者其他的函数中,若想要调用父类的被覆盖的函数,可以使用关键字super。例如super.sayHello();
即表示父类的sayHello方法。
抽象类
我们使用关键字abstruct来定义抽象类和抽象方法,实例代码如下所示:
// 定义一个抽象类
abstract class Person {
name: string
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
abstract sayHello(): void;
}
class Asian extends Person {
skin: string;
constructor(name: string, age: number, skin: string) {
super(name, age);
this.skin = skin;
}
sayHello(): void {
console.log("你好,我叫" + this.name)
}
}
var asian = new Asian("王大彪", 20, "yello");
asian.sayHello()
我们看到我们使用abstruct
关键字修饰类Person
的定义,此时Person
类被定义成抽象类,抽象类不能直接新建,例如不能new Person()
。然后我们也使用abstruct
修饰了方法sayHello
,我们没有定义这个抽象方法的具体实现,只是定义了这个方法的参数和返回值的类型。它的具体实现是在其子类Asian中定义的。
接口
在TS中我们使用interface关键字定义接口。示例代码如下所示:
// 定义一个接口,接口用于定义一个功能
interface Say {
sayHello(): void;
}
class Person implements Say{
name:string;
constructor(name: string) {
this.name = name;
}
sayHello(): void {
console.log("你好,我叫" + this.name);
}
}
var person = new Person("王铁柱");
person.sayHello();
我们可以看到我们使用interface
定义了一个接口Say
,表示了说话的功能。我们定义了一个类Person
,使用关键字implements
表明它实现接口Say
,这就表明了类Person
拥有说话的能力,并实现了方法sayHello
方法。
属性的修饰符
类的属性有三种修饰符,表示了属性可以使用的范围。代码示例如下所示:
class Person {
public _name: string;
protected _age: number;
private _money:number;
constructor(name: string, age: number, money: number) {
this._name = name;
this._age = age;
this._money = money;
}
get age(): number {
return this._age;
}
set age(value: number) {
this._age = value;
}
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
get money(): number {
return this._money;
}
set money(value: number) {
this._money = value;
}
}
var person = new Person("王铁牛", 30, 100);
console.log(person.name);
我们可以看到类Person分别有三个属性,这三个属性分别使用了三种不同的修饰符。
- public:可以在类外直接使用该属性。
- protected:只能在当前类及其子类中使用该属性
- private:只能在当前类使用该属性
泛型
在TS中也可以使用泛型的概念,代码示例如下:
class Person<T> {
skin:T;
constructor(skin: T) {
this.skin = skin;
}
}
class Skin{
color: string;
constructor(color: string) {
this.color = color;
}
}
var person = new Person<Skin>(new Skin("yello"));
var person1 = new Person<string>("white");
console.log(person.skin.color);
console.log(person1.skin);
对于类Person
,我们将皮肤的类型定义成泛型,所以我们既可以将类Skin
作为Person
的skin
属性的类型,也可以直接将string
作为skin
属性的类型,这就是泛型的使用。