TypeScript

  • TypeScript是JavaScript类型的超集,它可以编译成纯avaScript
  • TypeScripti可以在任何览器、任何计算机和任何操作系统上运行,并且是开源的
  • Reference: 尚硅谷 - TypeScript
  • Website:

1 TypeScript 基础

1.1 简介

  • TypeScript

    • 以 JavaScript 为基础构建的语言
    • TypeScript 是 JavaScript 的超集
    • 可以在任何支持 JavaScript 的平台中执行
      • TS完全兼容JS,换言之,任何的JS代码都可以直接当成JS使用
      • TS不能被JS解析器直接执行:TS代码需要通过编译器编译为JS,然后再交由JS解析器执行
    • TypeScript 扩展了 JavaScript,并添加了类型等许多新的概念
  • 比较

    • TS拥有了静态类型,更加严格的语法,更强大的功能
    • TS可以在代码执行前就完成代码的检查,减小了运行时异常的出现的几率
    • TS代码可以编译为任意版本的JS代码,可有效解决不同JS运行环境的兼容问题
    • 同样的功能,TS的代码量要大于JS,但由于TS的代码结构更加清晰,变量类型更加明确,在后期代码的维护中TS却远远胜于JS

1.2 开发环境搭建

  1. Node.js

  2. 全局安装typescript npm i -g typescript

  3. 使用 tsc 对 ts 文件进行编译 tsc xxx.ts

2 基本类型

2.1 类型声明

  • 类型声明是TS非常重要的一个特点

    • 通过类型声明可以指定TS中变量(参数、形参)的类型
    • 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错
  • 语法:

    • ```typescript
      let 变量: 类型;

      let 变量: 类型 = 值;

      function fn(参数: 类型, 参数: 类型): 类型{

      ...
      

      }

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31

      ## 2.2 自动类型判断机制

      - 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
      - 所以如果你的变量的声明和赋值时**同时进行**的,可以**省略掉类型声明**

      ## 2.3 类型

      | 类型 | 例子 | 描述 |
      | :-----: | :---------------: | :----------------------------: |
      | 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中新增类型 |

      ### 2.3.1 number

      - ```typescript
      let decimal: number = 6;
      let hex: number = 0xf00d;
      let binary: number = 0b1010;
      let octal: number = 0o744;
      let big: bigint = 100n;

2.3.2 boolean

  • ```typescript
    let isDone: boolean = false;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    ### 2.3.3 string

    - ```typescript
    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.`;

2.3.4 字面量

  • 也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围

  • ```typescript
    let color: ‘red’ | ‘blue’ | ‘black’;
    let num: 1 | 2 | 3 | 4 | 5;

    1
    2
    3
    4
    5
    6
    7

    ### 2.3.5 any

    - ```typescript
    let d: any = 4;
    d = 'hello';
    d = true;

:key: 对其他类型进行any赋值,会更改此变量类型为any

2.3.6 unknown

  • ```typescript
    let notSure: unknown = 4;
    notSure = ‘hello’;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    :key: 类型安全的 `any`: 对其他类型进行unknown赋值,会报错

    ### 2.3.7 void

    - ```typescript
    let unusable: void = undefined;
    function fn(): void {
    return;
    return null;
    return undefined;
    }

2.3.8 never

  • ```typescript
    function error(message: string): never {
    throw new Error(message);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    ### 2.3.9 object 限制对象

    - ```typescript
    let obj: object = {};

    // {} 用来指定对象中可以包含哪些属性
    // 语法:{属性名:属性值,属性名:属性值}
    // 在属性名后面加上?,表示属性是可选的
    let obj: { name: string; age?: number };
    obj = { name: "张三" };

    // [propName: string]: any 表示可以添加任意属性,任意属性的值可以是任意类型
    let obj2: { name: string; [propName: string]: any };
    obj2 = { name: "李四", sex: "男", age: 18 };

    // 设置函数结构的类型声明
    let funObj: (a: number, b: number) => number;
    funObj = function (a: number, b: number): number {
    return a + b;
    };

2.3.10 array

  • ```typescript
    let list: number[] = [1, 2, 3];
    let list: Array = [1, 2, 3];
    1
    2
    3
    4
    5
    6

    ### 2.3.11 tuple

    - ```typescript
    let x: [string, number];
    x = ["hello", 10];

2.3.12 enum

  • ```typescript
    enum Color {
    Red,
    Green,
    Blue,
    }
    let c: Color = Color.Green;

    enum Color {
    Red = 1,
    Green,
    Blue,
    }
    let c: Color = Color.Green;

    enum Color {
    Red = 1,
    Green = 2,
    Blue = 4,
    }
    let c: Color = Color.Green;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    ## 2.4 类型断言

    - 有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式:

    - 第一种

    - ```typescript
    let someValue: unknown = "this is a string";
    let strLength: number = (someValue as string).length;
    • 第二种

      • ```typescript
        let someValue: unknown = “this is a string”;
        let strLength: number = (someValue).length;
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38


        # 3 编译选项

        ## 3.1 自动编译文件 -w

        > 编译文件时,使用 -w 指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。

        - `tsc xxx.ts -w/--watch`

        ## 3.2 自动编译整个项目 tsconfig.json

        ### 3.2.1 简介

        - `tsconfig.json`
        - 如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。

        - 但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件 tsconfig.json

        - tsconfig.json是一个JSON文件,添加配置文件后,只需只需 tsc 命令即可完成对整个项目的编译


        - 使用
        - 不带任何输入文件的情况下调用`tsc`,编译器会从当前目录开始去查找`tsconfig.json`文件,逐级向上搜索父目录
        - 不带任何输入文件的情况下调用`tsc`,且使用命令行参数`--project`(或`-p`)指定一个包含`tsconfig.json`文件的目录

        ### 3.2.2 配置选项

        #### 1)include

        - 定义希望被编译文件所在的目录

        - 默认值:["\*\*/\*"]

        - 示例:

        - ```json
        "include":["src/**/*", "tests/**/*"]
    • 上述示例中,所有src目录和tests目录下的文件都会被编译

  • * 匹配0或多个字符(不包括目录分隔符)
  • ? 匹配一个任意字符(不包括目录分隔符)
  • **/ 递归匹配任意子目录

2)exclude

  • 定义需要排除在外的目录

  • 默认值:["node_modules", "bower_components", "jspm_packages"]

  • 示例:

    • ```json
      “exclude”: [“./src/hello/*/“]

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11

      - 上述示例中,src下hello目录下的文件都不会被编译

      #### 3)extends

      - 定义被继承的配置文件

      - 示例:

      - ```json
      "extends": "./configs/base"
    • 上述示例中,当前配置文件中会自动包含config目录下base.json中的所有配置信息

4)files

  • 指定被编译文件的列表,只有需要编译的文件少时才会用到
1
2
3
4
5
6
7
8
9
10
11
"files": [
"core.ts",
"sys.ts",
"types.ts",
"scanner.ts",
"parser.ts",
"utilities.ts",
"binder.ts",
"checker.ts",
"tsc.ts"
]
  • 列表中的文件都会被TS编译器所编译

5)compilerOptions

  • 编译选项是配置文件中非常重要也比较复杂的配置选项
    • 在compilerOptions中包含多个子选项,用来完成对编译的配置

3.2.3 编译选项

1)项目基本选项

选项 示例 说明
target ES6 设置ts代码编译的目标版本
lib [“ES6”, “DOM”] 指定代码运行时所包含的库(宿主环境)
module commonjs 设置编译后代码使用的模块化系统
outDir dist 编译后文件的所在目录
默认情况下,编译后的js文件会和ts文件位于相同的目录,设置outDir后可以改变编译后文件的位置
outFile dist/app.js 将所有的文件编译为一个js文件
多模块引用合并仅支持”amd”和“system”模块
rootDir ./src 指定代码的根目录,默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过rootDir可以手动指定根目录
allowJs true 是否对js文件编译
checkJs true 是否对js文件进行检查
jsx preserve 指定 jsx 代码的生成: ‘preserve’, ‘react-native’, or ‘react’
removeComments false 是否删除注释
noEmit false 不对代码进行编译
sourceMap false 是否生成sourceMap
importHelpers true 从 tslib 导入辅助工具函数
isolatedModules true 将每个文件作为单独的模块 (与 ‘ts.transpileModule’ 类似)

2)严格检查

选项 说明
strict 启用所有的严格检查,默认值为true,设置后相当于开启了所有的严格检查
alwaysStrict 总是以严格模式对代码进行编译
noImplicitAny 禁止隐式的any类型
noImplicitThis 禁止类型不明确的this
strictBindCallApply 严格检查bind、call和apply的参数列表
strictFunctionTypes 严格检查函数的类型
strictNullChecks 严格的空值检查
strictPropertyInitialization 严格检查属性是否初始化

3)额外检查

选项 说明
noFallthroughCasesInSwitch 检查switch语句包含正确的break
noImplicitReturns 检查函数没有隐式的返回值
noUnusedLocals 检查未使用的局部变量
noUnusedParameters 检查未使用的参数
skipLibCheck 跳过所有声明文件的类型检查
skipDefaultLibCheck 只跳过默认声明文件的类型检查,也就是忽略检查带有 <reference no-default-lib="true"/>的文件。

4)高级检查

选项 说明
allowUnreachableCode 检查不可达代码(true: 忽略不可达代码)
noEmitOnError 有错误的情况下不进行编译

5)模块解析选项

选项 说明
moduleResolution 选择模块解析策略: ‘node’ (Node.js) or ‘classic’
baseUrl 用于解析非相对模块名称的基目录
paths 模块名到基于 baseUrl 的路径映射的列表
rootDirs 根文件夹列表,其组合内容表示项目运行时的结构内容
typeRoots 指定类型文件包所在的文件夹(文件夹下有多个包),未设置默认(指定包所在的文件夹)
types 需要包含的类型声明文件,未设置默认typeRoots指定文件夹下的所有包,设置后则仅按指定的包
allowSyntheticDefaultImports 允许从没有设置默认导出的模块中默认导入

6)源文件选项

选项 说明
sourceRoot 指定调试器应该找到 TypeScript 文件而不是源文件的位置
mapRoot 指定调试器应该找到映射文件而不是生成文件的位置
inlineSourceMap 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
inlineSources 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 —inlineSourceMap 或 —sourceMap 属性

7)其他选项

选项 说明
experimentalDecorators 启用装饰器
emitDecoratorMetadata 为装饰器提供元数据的支持

3.3 配置文件示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
/*
路径 ** 表示任意目录 * 表示任意文件
exclude: 默认值 ["node_modules", "bower_components", "jspm_packages"]
*/
"include": ["src/**/*"], // 包含的文件, ./src目录下的所有文件
"exclude": ["src/tests/**/*"], // 排除的文件, ./src/tests目录下的所有文件
"extends": "./tsconfig.base.json", // 继承的配置文件
"compilerOptions": {
/* 项目基本配置 */
"target": "ESNext", // 编译后的目标版本 [default: ES3] (ESNext: 最新版本)
"module": "CommonJS", // 模块化规范 [default: CommonJS]
// "lib": ["ES5", "DOM"], // 编译过程中需要引入的库文件 [default: ES5, DOM] (一般不用改)
"outDir": "./dist", // 编译后的文件输出目录 [default: ./dist]
// "outFile": "./dist/bundle.js" // 编译后的文件输出路径 [default: undefined] (通常需要配合module: "AMD"或"system"使用)
"allowJs": false, // 是否允许编译js文件 [default: false]
"checkJs": false, // 是否检查js文件 [default: false]
"removeComments": true, // 是否移除注释 [default: false]
"noEmit": false, // 是否不输出文件 [default: false] (只检查语法错误, 不输出文件)
"noEmitOnError": true, // 是否在有错误时不输出文件 [default: false]

/* 语法检查 */
"strict": true, // 是否开启所有严格类型检查 [default: false] (所有严格检查全部打开, 需要单独进行可选项的关闭)
"alwaysStrict": true, // 是否在编译过程中加入"use strict" [default: false] (ES6代码默认开启严格模式)
"noImplicitAny": true, // 是否不允许隐式的any类型 [default: false]
"noImplicitThis": true, // 禁止类型不明确的this [default: false]
"strictNullChecks": true, // 是否开启严格的null检查 [default: false]
}
}

4 webpack

通常情况下,实际开发中我们都需要使用构建工具对代码进行打包,TS同样也可以结合构建工具一起使用,下边以webpack为例介绍一下如何结合构建工具使用TS。

4.1 初始化

  • 项目根目录 npm init -y
    • 创建 package.json 文件

4.2 安装依赖

  • npm i webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin html-webpack-plugin -D
依赖 说明
webpack 构建工具webpack
webpack-cli webpack的命令行工具
webpack-dev-server webpack的开发服务器
typescript ts编译器
ts-loader ts加载器,用于在webpack中编译ts文件
html-webpack-plugin webpack中html插件,用来自动创建html文件
clean-webpack-plugin webpack中的清除插件,每次构建都会先清除目录

4.3 webpack.config.js

  • ```js
    const path = require(“path”);
    const HtmlWebpackPlugin = require(“html-webpack-plugin”);

    const isProduction = process.env.NODE_ENV === “production”;

    module.exports = {
    entry: “./src/index.ts”,
    output: {

    path: isProduction ? path.resolve(__dirname, "dist") : undefined,
    filename: "bundle.js",
    environment: {
      arrowFunction: false, // 关闭webpack的箭头函数
    },
    clean: true, // 清理dist目录
    

    },
    module: {

    rules: [
      {
        test: /\.ts$/,
        loader: "ts-loader",
        exclude: /node_modules/,
      },
    ],
    

    },
    plugins: [

    new HtmlWebpackPlugin({
      // 生成html文件
      title: "TS测试", // html文件的title
    }),
    

    ],
    optimization: {

    minimize: false,
    

    },
    devtool: “inline-source-map”, // 错误追踪
    resolve: {

    extensions: [".ts", ".js"], // 引入文件时,可以省略后缀名
    

    },
    devServer: {

    open: true,
    host: "localhost",
    port: 3000,
    hot: true,
    historyApiFallback: true,
    

    },
    mode: isProduction ? “production” : “development”,
    };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    ## 4.4 tsconfig.json

    - ```json
    {
    "include": ["src/**/*"],
    "compilerOptions": {
    "target": "ES6",
    "module": "ES6",
    "strict": true
    }
    }

4.5 修改package.json添加如下配置

  • ```json
    “scripts”: {
    “start”: “npm run dev”,
    “dev”: “cross-env NODE_ENV=development webpack serve”,
    “build”: “cross-env NODE_ENV=production webpack”
    },
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    ## 4.6 执行

    - `npm run build` 打包
    - `npm run start` 执行

    # 5 Babel

    > 经过一系列的配置,使得TS和webpack已经结合到了一起,除了webpack,开发中还经常需要结合babel来对代码进行转换以使其可以兼容到更多的浏览器,在上述步骤的基础上,通过以下步骤再将babel引入到项目中。

    ## 5.1 安装依赖

    - `npm i -D @babel/core @babel/preset-env babel-loader core-js`

    | 依赖 | 说明 |
    | ----------------- | ----------------------------------------- |
    | @babel/core | babel的核心工具 |
    | @babel/preset-env | babel的预定义环境 |
    | @babel-loader | babel在webpack中的加载器 |
    | core-js | core-js用来使老版本的浏览器支持新版ES语法 |

    ## 5.2 修改webpack.config.js

    ```js
    // webpack.config.js
    module: {
    rules: [
    {
    test: /\.ts$/,
    use: ["babel-loader", "ts-loader"],
    exclude: /node_modules/,
    },
    ],
    },
1
2
3
4
5
6
7
8
9
10
// babel.config.js
module.exports = {
presets: ["@babel/preset-env"],
targets: {
chrome: "58",
ie: "11",
},
corejs: "3",
useBuiltIns: "usage",
};

6 面向对象简介

  • 面向对象是程序中一个非常重要的思想,简而言之就是程序之中所有的操作都需要通过对象来完成。

    • 举例来说:
      • 操作浏览器要使用window对象
      • 操作网页要使用document对象
      • 操作控制台要使用console对象
  • 在程序中所有的对象都被分成了两个部分数据和功能,以人为例,人的姓名、性别、年龄、身高、体重等属于数据,人可以说话、走路、吃饭、睡觉这些属于人的功能。数据在对象中被成为属性,而功能就被称为方法。所以简而言之,在程序中一切皆是对象。

7 类(class)

  • 所谓的类可以理解为对象的模型,程序中可以根据类创建指定类型的对象
1
2
3
4
5
6
7
8
9
10
11
class 类名 {
属性名: 类型;

constructor(参数: 类型){
this.属性名 = 参数;
}

方法名(){
....
}
}

8 面向对象的特点

8.1 封装

  • 对象实质上就是属性和方法的容器,它的主要作用就是存储属性和方法,这就是所谓的封装
  • 默认情况下,对象的属性是可以任意的修改的,为了确保数据的安全性,在TS中可以对属性的权限进行设置
  • 只读属性(readonly):

    • 如果在声明属性时添加一个readonly,则属性便成了只读属性无法修改

8.2 属性修饰符:

  • public(默认值),可以在类、子类和对象中修改
  • protected ,可以在类、子类中修改
  • private ,可以在类中修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person {
private count: number = 0; // private: 只能在类内部访问
name: string;
age: number;
static type: string = "人类"; // static: 静态属性,可以通过类名直接访问

constructor(name: string, age: number) {
this.name = name;
this.age = age;
this.count++;
}

sayHello() {
console.log(`Hello, ${this.name}`);
}

get getCount() {
return this.count;
}
}

8.3 属性存取器

  • 对于一些不希望被任意修改的属性,可以将其设置为private

  • 直接将其设置为private将导致无法再通过对象修改其中的属性

  • 我们可以在类中定义一组读取、设置属性的方法,这种对属性读取或设置的属性被称为属性的存取器

  • 读取属性的方法叫做setter方法,设置属性的方法叫做getter方法

  • 示例:

    • ```ts
      class Person {
      private count: number = 0; // private: 只能在类内部访问
      name: string;
      private _age: number;
      static type: string = “人类”; // static: 静态属性,可以通过类名直接访问

      constructor(name: string, age: number) {

      this.name = name;
      this._age = age;
      this.count++;
      

      }

      sayHello() {

      console.log(`Hello, ${this.name}`);
      

      }

      get age() {

      return this._age;
      

      }

      set age(age: number) {

      if (age < 0) {
        throw new Error("年龄不能为负数");
      }
      this._age = age;
      

      }

      get getCount() {

      return this.count;
      

      }
      }

      const p = new Person(“张三”, 18);
      console.log(name: ${p.name}, age: ${p.age}, type: ${Person.type});
      console.log(“一年过去后….”);
      p.age++;
      console.log(name: ${p.name}, age: ${p.age}, type: ${Person.type});

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30

      ## 8.4 静态属性

      - 静态属性(方法),也称为类属性。使用静态属性无需创建实例,通过类即可直接使用
      - 静态属性(方法)使用static开头

      ```ts
      class MyMath {
      static PI: number = 3.1416;
      static add(...args: number[]) {
      return args.reduce((prev, curr) => prev + curr, 0);
      }
      static sub(x: number, y: number) {
      return x - y;
      }

      static mul(...args: number[]) {
      return args.reduce((prev, curr) => prev * curr, 1);
      }

      static div(x: number, y: number) {
      return x / y;
      }
      }

      console.log(`PI: ${MyMath.PI}`);
      console.log(`add: ${MyMath.add(1, 2, 3, 4, 5)}`);
      console.log(`sub: ${MyMath.sub(10, 5)}`);
      console.log(`mul: ${MyMath.mul(1, 2, 3, 4, 5)}`);
      console.log(`div: ${MyMath.div(10, 5)}`);

8.5 this

  • 在类中,使用this表示当前对象\
1
2
3
4
5
const p1 = new Person();
const p2 = new Person();

p1.getThis -> p1
p2.getThis -> p2

8.6 继承

  • 继承时面向对象中的又一个特性

  • 通过继承可以将其他类中的属性和方法引入到当前类中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}

class Dog extends Animal {
age: number;

constructor(name: string, age: number) {
super();
this.age = age;
}

bark() {
console.log("Woof! Woof!");
}
}

class Cat extends Animal {
meow() {
console.log("Meow! Meow!");
}
}

const dog = new Dog("dog");
dog.bark();
const cat = new Cat("cat");
cat.meow();
  • 通过继承可以在不修改类的情况下完成对类的扩展

8.7 重写

  • 发生继承时,如果子类中的方法会替换掉父类中的同名方法,这就称为方法的重写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Animal{
name: string;
age: number;

constructor(name: string, age: number){
this.name = name;
this.age = age;
}

run(){
console.log(`父类中的run方法!`);
}
}

class Dog extends Animal{

bark(){
console.log(`${this.name}在汪汪叫!`);
}

run(){
console.log(`子类中的run方法,会重写父类中的run方法!`);
}
}

const dog = new Dog('旺财', 4);
dog.bark();
  • 在子类中可以使用super来完成对父类的引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}

bark() {
console.log("Animal bark");
}
}

class Dog extends Animal {
bark() {
console.log("Woof! Woof!");
super.bark();
}
}

const dog = new Dog("dog");
dog.bark();

8.8 抽象类(abstract class)

  • 抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例
1
2
3
4
5
6
7
8
9
10
11
12
abstract class Animal{
abstract run(): void;
bark(){
console.log('动物在叫~');
}
}

class Dog extends Animals{
run(){
console.log('狗在跑~');
}
}
  • 使用abstract开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要实现

9 接口(Interface)

接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
interface Person{
name: string;
sayHello():void;
}

class Student implements Person{
constructor(public name: string) {
}

sayHello() {
console.log('大家好,我是'+this.name);
}
}
  • 示例(检查对象类型):

    • ```typescript
      interface Person{

      name: string;
      sayHello():void;
      

      }

      function fn(per: Person){

      per.sayHello();
      

      }

      fn({name:’孙悟空’, sayHello() {console.log(Hello, 我是 ${this.name})}});

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11

      # 10 泛型(Generic)

      > 定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。

      - 泛型

      - ```typescript
      function test<T>(arg: T): T{
      return arg;
      }
    • 这里的<T>就是泛型,T是我们给这个类型起的名字(不一定非叫T),设置泛型后即可在函数中使用T来表示该类型。所以泛型其实很好理解,就表示某个类型。

  • 使用

    • 方式一(直接使用):

      • ```typescript
        test(10)
        1
        2
        3
        4
        5

        - 方式二(指定类型):

        - ```typescript
        test<number>(10)
  • 可以同时指定多个泛型,泛型间使用逗号隔开

    • ```typescript
      function test(a: T, b: K): K{

      return b;
      

      }

      test(10, “hello”);

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13

      - 使用泛型时,完全可以将泛型当成是一个普通的类去使用

      - 类中同样可以使用泛型:

      - ```typescript
      class MyClass<T>{
      prop: T;

      constructor(prop: T){
      this.prop = prop;
      }
      }
  • 也可以对泛型的范围进行约束

    • interface MyInter{
          length: number;
      }
      
      function test<T extends MyInter>(arg: T): number{
          return arg.length;
      }
      
    • 使用T extends MyInter表示泛型T必须是MyInter的子类,不一定非要使用接口类和抽象类同样适用。