TS笔记


1. 什么是TypeScript

TS与JS.png

TypeScript 是 JavaScript 的一个超集,主要提供了类型系统对 ES6+ 的支持,它由 Microsoft 开发,代码开源于 GitHub (opens new window)

TypeScript 的特点:

  • 可编译成纯净、简洁的js代码以运行在多个平台上

  • 强大的静态类型和代码完成

  • 提供js的ES6特性

2.基本类型

类型特性

类型声明

  • 通过:指定TS中变量(参数、形参)的类型;

  • 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错;

  • 简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值;

    语法:

    let 变量: 类型;
    
    let 变量: 类型 =;
    
    function fn(参数: 类型, 参数: 类型): 返回值类型{}

类型断言

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

  • 第一种 as

    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编译器会自动判断变量的类型

/* 定义变量时赋值了, 推断为对应的类型 */
let b9 = 123 // number
// b9 = 'abc' // error

/* 定义变量时没有赋值, 推断为any类型(隐式推断,tsconfig中可关闭) */
let b10  // any类型
b10 = 123
b10 = 'abc'

类型别名

类似接口,但类型别名不能重复命名,接口可以

type MyType = 1 | 2 | 3 | 4;

联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种,使用|

function toString2(x: number | string) : string {
  return x.toString()
}

交叉类型

交叉类型表示取值同时属于多种类型,使用&

let a5: { name: string } & { age: number };
a5 = {name: 'haha', age: 18};

具体类型:

类型 例子 描述
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中新增类型
null和undefined 所有类型的子类型
  • 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 Bobbington`;
    let age: number = 37;
    let sentence: string = `Hello, my name is ${fullName}.
    
    I'll be ${age + 1} years old next month.`;
  • null和undefined

    let u: undefined = undefined
    let n: null = null

    默认情况下 nullundefined 是所有类型的子类型。 就是说你可以把 nullundefined赋值给任何类型的变量。(需要在tsconfig.json中关闭严格模式"strict": false

  • 字面量

    作用:确定变量的具体取值范围

    let color: 'red' | 'blue' | 'black';
    let num: 1 | 2 | 3 | 4 | 5;        // 可以限定num的范围只在1~5
  • any

    any类型可赋给任意类型的变量,因此可能造成错误,不安全

    let d: any = 4;
    let n: number;
    n = d;    // 编译通过,但有安全隐患
  • unknown

    unknown类型变量不能随意赋值,安全

    let what3: unknown;
    let what4: any;
    let what2: number = what4;    //    正常
    what2 = what3;    // 报错,不能将类型“unknown”分配给类型“number”。
  • void

    void常用于函数返回类型

    let unusable: void = undefined;
  • never

    never可用于函数报错

    function error(message: string): never {
      throw new Error(message);        
    }
  • object

    没啥用,一般会更具体的声明类型

    let obj: object = {};
  • array

    // 两种方式
    let list: number[] = [1, 2, 3];                // type[] 方式
    let list: Array<number> = [1, 2, 3];    // 泛型方式
  • tuple

    适用于已知元素数量和类型的数组,而各元素的类型有不相同的情况

    let x: [string, number];
    x = ["hello", 10]; 
  • enum

    个人认为与数据相反,数据:数字索引映射data;枚举:data映射数字

    enum Color {    // 为一组数值赋予友好的名字
      Red,                // 默认情况下,从0开始为元素编号
      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;    // 2
    console.log(Color[1])                // 由枚举的值得到它的名字 > Red

3.编译选项

自动编译单个文件

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

  tsc xxx.ts -w

自动编译整个项目

tsc -w

前提是项目根目录下有ts的配置文件 tsconfig.json

tsc --init

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

配置选项:

** =>所有文件夹;* => 所有文件

include

  • 定义希望被编译文件所在的目录
  • 默认值:[“**/*“]
  "include":["src/**/*", "tests/**/*"]

exclude

  • 定义需要排除在外的目录
  • 默认值:[“node_modules”, “bower_components”, “jspm_packages”]
  "exclude": ["./src/hello/**/*"]

extends

  • 定义要扩展的配置文件
"extends": "./configs/base"

上述示例中,当前配置文件中会自动包含config目录下base.json中的所有配置信息

files

  • 指定被编译文件的列表,只有需要编译的文件少时才会用到
"files": [
    "core.ts",
    "sys.ts",
    "types.ts",
    "scanner.ts",
    "parser.ts",
    "utilities.ts",
    "binder.ts",
    "checker.ts",
    "tsc.ts"
  ]

compilerOptions

  • target

    • 设置ts代码编译的目标版本

    • 可选值:ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext

      "compilerOptions": {
          "target": "ES6"        // 编译为ES6
      }
  • lib

    • 指定代码运行时所包含的库(宿主环境)

    • 可选值:DOM、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、WebWorker、ScriptHost ……

      "compilerOptions": {
          "target": "ES6",
          "lib": ["ES6", "DOM"],
          "outDir": "dist",
          "outFile": "dist/aa.js"
      }
  • module

    • 设置编译后代码使用的模块化系统

    • 可选值:CommonJS、UMD、AMD、System、ES2020、ESNext、None

      "compilerOptions": {
          "module": "CommonJS"
      }
  • outDir

    • 编译后文件的所在目录

    • 默认情况下,编译后的js文件会和ts文件位于相同的目录,设置outDir后可以改变编译后文件的位置

      "compilerOptions": {    
          "outDir": "dist"    //    设置后编译后的js文件将会生成到dist目录
      }
  • outFile

    • 将所有的文件编译为一个js文件

    • 默认会将所有的编写在全局作用域中的代码合并为一个js文件,如果module制定了None、System或AMD则会将模块一起合并到文件之中,为其他模块化规范则不起作用

      "compilerOptions": {  
        "outFile": "dist/app.js"
      }
  • rootDir

    • 指定代码的根目录

    • 默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过rootDir可以手动指定根目录

  ```json
  "compilerOptions": {  
    "rootDir": "./src"
  }
  ```
  • allowJs

    • 是否对js文件编译
  • checkJs

    • 是否对js文件进行检查

      "compilerOptions": {  
        "allowJs": true,  
        "checkJs": true
      }
  • removeComments

    • 是否删除注释
    • 默认值:false
  • noEmit

    • 不对代码进行编译,只检查语法
    • 默认值:false
  • noEmitOnError

    • 有错误的情况下不进行编译

    • 默认值:false

    • sourceMap

      • 是否生成sourceMap
    • 默认值:false

严格检查

  • strict :启用所有的严格检查,默认值为true,设置后相当于开启了后面所有的严格检查

  • alwaysStrict :总是以严格模式对代码进行编译

  • noImplicitAny :禁止隐式的any类型

  • noImplicitThis :禁止类型不明确的this

  • strictBindCallApply :严格检查bind、call和apply的参数列表

  • strictFunctionTypes :严格检查函数的类型

  • strictNullChecks :严格的空值检查

  • strictPropertyInitialization :严格检查属性是否初始化

额外检查

  • noFallthroughCasesInSwitch:检查switch语句包含正确的break

  • noImplicitReturns:检查函数没有隐式的返回值

  • noUnusedLocals:检查未使用的局部变量

  • noUnusedParameters:检查未使用的参数

  • allowUnreachableCode:检查不可达代码

TypeScript打包

webpack整合

初始化项目

进入项目根目录,执行命令 npm init -y,创建package.json文件

下载构建工具

npm install -D 
webpack                             //    构建工具webpack
webpack-cli                     //    webpack的命令行工具
webpack-dev-server         //    webpack的开发服务器
typescript                         //    ts编译器
ts-loader                         //    ts加载器,用于在webpack中编译ts文件
clean-webpack-plugin  //    用来自动创建html文件
html-webpack-plugin      //    每次构建都会先清除目录
cross-env                            //    统一环境变量

配置webpack

根目录下创建webpack的配置文件webpack.config.js

const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

const isProd = process.env.NODE_ENV === 'production' // 是否生产环境

function resolve (dir) {
 return path.resolve(__dirname, '..', dir)
}

module.exports = {
 mode: isProd ? 'production' : 'development',
 entry: {
   app: './src/main.ts'
 },

 output: {
   path: resolve('dist'),
   filename: '[name].[contenthash:8].js'
 },

 module: {
   rules: [
     {
       test: /\.tsx?$/,
       use: 'ts-loader',
       include: [resolve('src')]
     }
   ]
 },

 plugins: [
   new CleanWebpackPlugin({
   }),

   new HtmlWebpackPlugin({
     template: './public/index.html'
   })
 ],

 resolve: {
   extensions: ['.ts', '.tsx', '.js']
 },

 devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map',

 devServer: {
   host: 'localhost', // 主机名
   stats: 'errors-only', // 打包日志输出输出错误信息
   port: 8081,
   open: true
 },
}

配置TS编译选项

根目录下创建tsconfig.json,配置可以根据自己需要

{
   "compilerOptions": {
       "target": "ES2015",
       "module": "ES2015",
       "strict": true
   }
}

修改package.json配置

修改package.json添加如下配置

{
   ...
   "scripts": {
       "test": "echo \"Error: no test specified\" && exit 1",
      "dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
            "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
   },
   ...
}

项目使用

在src下创建ts文件,并在并命令行执行npm run build对代码进行编译;

或者执行npm run dev来启动开发服务器;


Babel

除了webpack,开发中还经常需要结合babel来对代码进行转换;

以使其可以兼容到更多的浏览器,在上述步骤的基础上,通过以下步骤再将babel引入到项目中;

虽然TS在编译时也支持代码转换,但是只支持简单的代码转换;

对于例如:Promise等ES6特性,TS无法直接转换,这时还要用到babel来做转换;

安装依赖包

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

修改webpack.config.js配置文件

...
module: {
    rules: [
        {
            test: /\.ts$/,
            use: [
                {
                    loader: "babel-loader",
                    options:{
                        presets: [
                            [
                                "@babel/preset-env",
                                {
                                    "targets":{
                                        "chrome": "58",
                                        "ie": "11"
                                    },
                                    "corejs":"3",
                                    "useBuiltIns": "usage"
                                }
                            ]
                        ]
                    }
                },
                {
                    loader: "ts-loader",

                }
            ],
            exclude: /node_modules/
        }
    ]
}
...

如此一来,使用ts编译后的文件将会再次被babel处理;

使得代码可以在大部分浏览器中直接使用;

同时可以在配置选项的targets中指定要兼容的浏览器版本;

8. 函数

函数是 JavaScript 应用程序的基础,它帮助你实现抽象层,模拟类,信息隐藏和模块。在 TypeScript 里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义行为的地方。TypeScript 为 JavaScript 函数添加了额外的功能,让我们可以更容易地使用。

函数类型

let myAdd2: (x: number, y: number) => number = function(x: number, y: number): number {
  return x + y
}

function add(x: number, y: number): number {
  return x + y
}

let myAdd = function(x: number, y: number): number {     // 能自动推断myAdd类型
  return x + y
}

我们可以给每个参数添加类型之后再为函数本身添加返回值类型。TypeScript 能够根据返回语句自动推断出返回值类型。

可选参数和默认参数

TypeScript 里的每个函数参数都是必须的。 这不是指不能传递 nullundefined 作为参数,而是说编译器检查用户是否为每个参数都传入了值。编译器还会假设只有这些参数会被传递进函数。 简短地说,传递给一个函数的参数类型和个数必须与函数期望的一致。

JavaScript 里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是 undefined。 在TypeScript 里我们可以在参数名旁使用 ? 实现可选参数的功能。 比如,我们想让 lastName 是可选的:

在 TypeScript 里,我们也可以为参数提供一个默认值当用户没有传递这个参数或传递的值是 undefined 时。 它们叫做有默认初始化值的参数。比如,把firstName 的默认值设置为 "A"

function buildName(firstName: string='A', lastName?: string): string {
  if (lastName) {
    return firstName + '-' + lastName
  } else {
    return firstName
  }
}

console.log(buildName('C', 'D'))
console.log(buildName('C'))
console.log(buildName())

剩余参数

必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在 JavaScript 里,你可以使用 arguments 来访问所有传入的参数。

在 TypeScript 里,你可以把所有参数收集到一个变量里:
剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是你在省略号( ...)后面给定的名字,你可以在函数体内使用这个数组。

function info(x: string, ...args: any[]) {
  console.log(x, args)
}
info('abc', 'c', 'b', 'a')

函数重载

自我思考:typescript和java的重载不同。出发点不同:ts从js出发,js本身传值就是任意类型的,ts重载就是为了限制函数传值类型的范围,而java传值有类型,java重载是为了扩充函数传值类型的范围。

函数重载: 函数名相同, 而形参不同的多个函数

/* 
需求: 我们有一个add函数,它可以接收2个string类型的参数进行拼接,也可以接收2个number类型的参数进行相加 
*/

// 重载函数声明
function add (x: string, y: string): string
function add (x: number, y: number): number

// 定义函数实现
function add(x: string | number, y: string | number): string | number {
  // 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 x + y
  if (typeof x === 'string' && typeof y === 'string') {
    return x + y
  } else if (typeof x === 'number' && typeof y === 'number') {
    return x + y
  }
}

console.log(add(1, 2))
console.log(add('a', 'b'))
// console.log(add(1, 'a')) // error

定义类

class 类名 {
    属性名: 类型;

    constructor(参数: 类型){        //    可以使用`constructor`定义一个构造器方法;
        this.属性名 = 参数;
    }

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

const p = new Person('孙悟空', 18);
p.sayHello();

注1:TS中只能有一个构造器方法!

属性可位于花括号内

class C{
    name: string;
    age: number

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

也可以直接将属性定义在构造函数中:

class C {
    constructor(public name: string, public age: number) {
    }
}

上面两种定义方法是完全相同的!

class A {
    protected num: number;
    constructor(num: number) {
        this.num = num;
    }
}

class X extends A {
    protected name: string;
    constructor(num: number, name: string) {
        super(num);            //    如果在X类中不调用super将会报错!
        this.name = name;
    }
}

属性修饰

对象实质上就是属性和方法的容器,它的主要作用就是存储属性和方法,这就是所谓的封装

  • public(默认值): 公开的外部也可以访问
  • protected :类内部和子类可以访问

  • private :只能类内部可以访问

  • 静态属性(static):声明为static的属性或方法不再属于实例,而是属于类的属性;

  • 可选属性(?):

    • 是可以对可能存在的属性进行预定义
    • 是可以捕获引用了不存在的属性时的错误。
  • 只读属性(readonly):

    • 将属性设置为只读的, 只读属性必须在默认声明时或构造函数里被初始化。

    • readonly与const:作为变量使用的话用 const,若作为属性则使用 readonly

存取器

TypeScript 支持通过 getters/setters 来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

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

class Person{    
  private _name: string;    
  constructor(name: string){   
    this._name = name;  
  }   
  get name(){                                      // 取
    return this._name;  
  }    
  set name(name: string){                //    存
    this._name = name;   
  }}
const p1 = new Person('孙悟空');    // 实际通过调用getter方法读取name属性
console.log(p1.name);                        // 实际通过调用setter方法修改name属性 p1.name = '猪八戒'; 

修饰参数属性(语法糖)

参数属性可以方便地让我们在constructor的参数列表里定义并初始化属性

class Person2 {
  constructor(public readonly name: string) {        //不再需要声明name属性并赋值,自动对应赋值
  }
}

const p = new Person2('jack')
console.log(p.name)

参数属性通过给构造函数参数前面添加一个访问限定符来声明。使用publicprotectedprivatereadonly都会在类中添加一个属性,但不包括static

继承

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

通过继承可以将其他类中的属性和方法引入到当前类中,通过super访问父类的属性

经典示例:

class Animal {
  name: string

  constructor (name: string) {
    this.name = name
  }

  run (distance: number=0) {
    console.log(`${this.name} run ${distance}m`)
  }

}

class Snake extends Animal {
  constructor (name: string) {
    // 必须调用父类型构造方法
    super(name)
  }

  // 重写父类型的方法
  run (distance: number=5) {
    console.log('sliding...')
    super.run(distance)
  }
}

class Horse extends Animal {
  constructor (name: string) {
    // 调用父类型构造方法
    super(name)
  }

  // 重写父类型的方法
  run (distance: number=50) {
    console.log('dashing...')
    // 子类中可以使用super来完成对父类的引用
    super.run(distance)    
  }

  xxx () {
    console.log('xxx()')
  }
}

const snake = new Snake('sn')
snake.run()

const horse = new Horse('ho')
horse.run()

// 父类型引用指向子类型的实例 ==> 多态
const tom: Animal = new Horse('ho22')
tom.run()

/* 如果子类型没有扩展的方法, 可以让子类型引用指向父类型的实例 */
const tom3: Snake = new Animal('tom3')
tom3.run()
/* 如果子类型有扩展的方法, 不能让子类型引用指向父类型的实例 */
// const tom2: Horse = new Animal('tom2')
// tom2.run()

注2:子类继承父类时,必须调用父类的构造方法(super)!

通过继承可以在不修改类的情况下完成对类的扩展

子类 ->派生类

超类 -> 基类

抽象类

抽象类(abstract class)是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例

abstract class Animal{ 
  abstract run(): void;  
  bark(){    
    console.log('动物在叫~'); 
  }}
class Dog extends Animals{ 
  run(){ 
    console.log('狗在跑~');
  }
}
  • 使用abstract开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,

  • 继承抽象类时抽象方法必须要实现;

  • 不能创建实例对象, 只有实现类才能创建实例

接口(Interface)

  • 接口的作用类似于抽象类,不同点在于:接口中的所有方法和属性都是没有实值的,都是抽象属性方法;而接口可以有实值
  • 接口是类的结构规范:对象只有包含(>=)接口中定义的所有属性和方法时才能匹配接口;
  • 可以让一个类去实现接口,实现接口时类中要实现接口中的所有属性方法;
  • 类似类型别名(type),但类型别名不能重复命名,接口可以
  • 一个类可以实现多个接口,用逗号隔开
  • 接口可以继承(extends)接口

用处:

  • 作为类类型检查对象类型:
interface Person{
    name: string;
    sayHello():void;
}

function fn(per: Person){        // here
    per.sayHello();
}

fn({name:'孙悟空', sayHello() {console.log(`Hello, 我是 ${this.name}`)}});
  • 作为类类型表示需实现的规范:
interface Person{
   name: string;
   sayHello():void;
}

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

   sayHello() {
       console.log('大家好,我是'+this.name);
   }
}
  • 作为函数类型

为了使用接口表示函数类型,我们需要给接口定义一个调用签名。它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。

// 接口可以描述函数类型(参数的类型与返回的类型)
interface SearchFunc {
  (source: string, subString: string): boolean
}

这样定义后,我们可以像使用其它接口一样使用这个函数类型的接口

const mySearch: SearchFunc = function (source: string, sub: string): boolean {
  return source.search(sub) > -1
}

console.log(mySearch('abcd', 'bc'))

泛型(Generic)

泛型就是类型变量

使用情景:无法确定函数和类中要使用的具体类型(返回值、参数、属性的类型不能确定);

泛型函数

创建泛型函数

可以同时指定多个泛型,泛型间使用逗号隔开:

function test<T,E>(arg: T): T{    // <T>就是泛型,表示某个类型;
    return arg;
}

使用泛型函数

方式一(直接使用,自动推断):

使用时可以直接传递参数使用,类型会由TS自动推断出来,但有时编译器无法自动推断时还需要使用下面的方式

test(10)
方式二(指定类型):

也可以在函数后手动指定泛型;

test<number>(10)

泛型类

类中同样可以使用泛型:

class MyClass<T>{
  prop: T;

  constructor(prop: T){
      this.prop = prop;
  }
}

泛型接口

在定义接口时, 为接口中的属性或方法定义泛型类型
在使用接口时, 再指定具体的泛型类型

interface IbaseCRUD <T> {
  data: T[]
  add: (t: T) => void
  getById: (id: number) => T
}

class User {
  id?: number; //id主键自增
  name: string; //姓名
  age: number; //年龄

  constructor (name, age) {
    this.name = name
    this.age = age
  }
}

class UserCRUD implements IbaseCRUD <User> {
  data: User[] = []

  add(user: User): void {
    user = {...user, id: Date.now()}
    this.data.push(user)
    console.log('保存user', user.id)
  }

  getById(id: number): User {
    return this.data.find(item => item.id===id)
  }
}


const userCRUD = new UserCRUD()
userCRUD.add(new User('tom', 12))
userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)

泛型继承(约束)

除此之外,也可以对泛型的范围进行约束

interface MyInter{
  length: number;
}

function test<T extends MyInter>(arg: T): number{
  return arg.length;
}

使用T extends MyInter表示泛型T必须是MyInter的子类,不一定非要使用接口类和抽象类同样适用;

10. 其它

声明文件

当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能

假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过 <script> 标签引入 jQuery,然后就可以使用全局变量 $jQuery 了。

但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西

jQuery('#foo');        // ERROR: Cannot find name 'jQuery'.

如果需要ts对新的语法进行检查, 需要要加载了对应的类型说明代码

可以自己写声明语句:

declare var jQuery: (selector: string) => any;

jQuery('#foo');

declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是:

jQuery('#foo');

但通常是下载声明文件到node_modules的@types中,很多的第三方库都定义了对应的声明文件库, 库文件名一般为 @types/xxx,有的第三库在下载时就会自动下载对应的声明文件库(比如: webpack),有的可能需要单独下载(比如jQuery/react)

npm install @types/jquery --save-dev

声明文件: 把声明语句放到一个单独的xxx.d.ts文件(jQuery.d.ts)中,将声明语句定义其中, TS编译器会扫描并加载项目中所有的TS声明文件

内置对象

JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。

内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准。

  1. ECMAScript 的内置对象

Boolean
Number
String
Date
RegExp
Error

/* 1. ECMAScript 的内置对象 */
let b: Boolean = new Boolean(1)
let n: Number = new Number(true)
let s: String = new String('abc')
let d: Date = new Date()
let r: RegExp = /^1/
let e: Error = new Error('error message')
b = true
// let bb: boolean = new Boolean(2)  // error
  1. BOM 和 DOM 的内置对象

Window
Document
HTMLElement
DocumentFragment
Event
NodeList

const div: HTMLElement = document.getElementById('test')
const divs: NodeList = document.querySelectorAll('div')
document.addEventListener('click', (event: MouseEvent) => {
  console.dir(event.target)
})
const fragment: DocumentFragment = document.createDocumentFragment()

文章作者: liheng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 liheng !
 上一篇
Linux笔记 Linux笔记
Linux入门1. Linux介绍 Linux 是一款免费,开源,安全,高效,稳定,处理高斌发很强悍的操作系统 Linux创始人——linux(林纳斯) Linux主要发行版本 2. Unix与Linux的关系2.1 Unix来源 2.
2021-07-19 liheng
下一篇 
webpack笔记 webpack笔记
webpack笔记第 1 章: webpack 简介1. 1 webpack 是什么webpack是一种前端资源构建工具,一个静态模块打包器(modulebundler)。在webpack看来,前端的所有资源文件(js/json/css/i
2021-02-02 liheng
  目录