【2w+字笔记】前端的你用得上的TypeScript入门指北🧭

前言

TypeScript 是一种由微软开发的开源编程语言,它是 JavaScript 的超集,为 JavaScript 提供了静态类型检查和面向对象编程的能力。与传统的 JavaScript 相比,TypeScript 强调类型安全和代码可维护性,使开发者能够更轻松地编写可靠的大型应用程序。

TypeScript 的优势体现在以下几个方面:

  • 静态类型检查TypeScript 引入了静态类型系统,使开发者能够在编码阶段捕获潜在的类型错误,提高代码质量和可靠性。类型检查还能提供代码补全、重构和文档化的功能,提高开发效率。
  • 面向对象编程TypeScript 支持类、接口、继承等面向对象编程的特性,使代码更具结构性和可读性。通过类的定义和继承,开发者可以更好地组织和重用代码。
  • JavaScript 生态系统的无缝整合TypeScriptJavaScript 的超集,现有的 JavaScript 代码可以无缝迁移到 TypeScript 中,并且 TypeScript 可以直接使用 JavaScript 的库和框架,扩展了开发者的选择和灵活性。
  • 强大的工具支持TypeScript 提供了强大的编译器和开发工具支持,包括代码补全、语法高亮、重构等功能。此外,许多流行的编辑器和集成开发环境(IDE)都提供了对 TypeScript 的良好支持,如Visual Studio CodeWebStorm 等。

TypeScript开发环境

安装

全局安装Typescript

bash 复制代码
npm install -g typescript

// 查看版本
tsc -v

初始化配置文件,创建 TypeScript 的项目配置文件: tsconfig.json。通过--locale zh-CN 命令创建出来的配置都是中文。

bash 复制代码
tsc --init --locale zh-CN

编译执行

编译ts文件

bash 复制代码
tsc index.ts

编译完成后会在目录下生成对应文件名的.js文件,里面就是编译后的代码,然后再执行这个.js文件就可以看到结果。

这样做太麻烦了,可以安装ts-node快速执行.ts文件

bash 复制代码
npm i ts-node -g

以后执行编译就可以通过这个命令

bash 复制代码
ts-node index.ts

VsCode插件

TypeScript Importer插件可以自动搜索文件中的TypeScript定义

Error Lens 插件可以将语法错误,直接显示在当前代码后面,例如

Playground TypeScript在线工具,还提供了ts配置文件选择

VsCode配置TypeScript类型提示,可以自动获取数据类型并在代码里面提示你。

打开首选项设置, 在搜索框输入TypeScript Inlay Hints,然后根据自己的需求打开提示。注意要勾选TypeScript开头的配置,如果勾选JavaScript就表示js文件也生效,建议只打开TypeScript文件就行。

ts文件中效果就是这样

当ts报错时,提示的报错信息为英文,通过设置可以将报错信息改为中文,更方便排查。

打开设置,在搜索栏输入typescript locale ,将选项选择为zh-CN

现在报错就都是中文

tsc编译阶段,也可以通过tsc demo.ts --locale zh-CN 来查看中文错误

TypeScrtip基础

数据类型

原始数据类型

字符串

使用string定义类型

ts 复制代码
const str:string = '泰裤辣'

还可以使用模版字符串

ts 复制代码
const name: string = '法外狂徒张三'
const age: number = 18
let sentence: string = `${name}今年${age}了` // "法外狂徒张三今年18了" 

数字

使用 number 定义数值类型,除了支持十进制和十六进制字面量,还支持二进制和八进制字面量

ts 复制代码
let decLiteral: number = 6
let hexLiteral: number = 0xf00d
let binaryLiteral: number = 0b1010
let octalLiteral: number = 0o744
let notANumber: number = NaN
let infinityNumber: number = Infinity

布尔

使用boolean定义类型

ts 复制代码
let booleand: boolean = true

空值

JavaScript没有空值Void概念,Typescript可以用Void表示没有任务返回值

ts 复制代码
function say(): void{
	console.log('泰裤辣')
}

void表示undefinednull

ts 复制代码
let u: void = undefined
let n: void = null

Null 和 Undefined

ts 复制代码
let u: undefined = undefined
let n: null = null

默认情况下nullundefined是所有类型的子类型 。 就是说可以把nullundefined赋值给number类型的变量,也可以赋值给string类型。

ts 复制代码
let test: void = undefined
let str: string = '泰裤辣'

str = test // ❌ 不能将类型"void"分配给类型"string"

换成null或者undefined就没问题

ts 复制代码
let test: null = null
let num: number = 2

num = test

注意! 如果tsconfig.json开启了严格模式 null 不能赋值 void 类型

json 复制代码
{
	"compileroptions": {
		...
		"strict": true
	}
}

any、unknown 、never

any

any任意类型,是一种动态类型,表示变量可以是任意类型的值。不清楚类型的变量类型,使用any就没有强制限定,随意切换。any 的本质是类型系统中的顶级类型,即 Top Types

在使用 any 类型时,TypeScript 编译器将不会对该变量进行类型检查,允许变量赋值为任何类型的值,以及调用任何方法和属性。

ts 复制代码
let str: any = '泰裤辣'

str = 123
str = true

或者变量在声明的时候没有制定类型,此时默认的为any

ts 复制代码
let anys
ayns = 123
ayns = true

开发过程中不知道用什么类型来表示,或者为了通过类型检测时,将类型设置为any就行,但这样就失去了TS类型检测的意义。

比如类型不兼容了就 any 一下,类型不想写了也 any 一下,不确定可能会是啥类型还是 any 一下,此时的 TypeScript 就变成了令人诟病的 AnyScript

unknown

unknown 类型是 TypeScript 3.0 引入的一种类型,表示变量的类型是未知的。

它和any一样,所有类型都可以分配给它,但是它不可以赋值给其他类型【any除外】

ts 复制代码
let str: unknown = '泰裤辣'
let num: number = 1
let anys: any = false

str = num
num = str // ❌ 不能将类型"unknown"分配给类型"number"。

// ✅ 赋值给 any 
anys = str

还有一个区别,unknown没有办法读任何属性,方法也不可以调用, 换成any就没问题。

在类型未知的情况下,更推荐使用 unknown 标注。

ts 复制代码
let person: unknown = {
  name: 'xg',
  say: () => {
      console.log('泰裤辣')
  }
}

person.name // ❌ "person"的类型为"未知"
person.say() // ❌ "person"的类型为"未知"

unknown 类型提供了一种更安全的方式来处理未知类型的数据,避免了潜在的运行时错误。

never

never类型表示永不存在的值的类型,不会携带任何类型信息,因此在联合类型中被直接忽略。

never 类型被称为 Bottom Types底层类型,是整个类型系统层级中最底层的类型。和 nullundefined 一样,它是所有类型的子类型。

ts 复制代码
type A = string | number | never

// 当鼠标移上去发现never类型消失了
type A = string | number

never类型是任何类型的子类型,也可以赋值给任何类型。但除了never本身外,其他类型不可以赋值给never

几个例子

ts 复制代码
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}

// 推断的返回值类型为never
function fail() {
    return error("Something failed");
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
    while (true) {
    }
}

never和void区别

  1. void类型只是没有返回值,但本身不会报错。never 类型表示那些永远不会发生的值的类型。当一个函数永远不会返回(例如抛出异常、进入无限循环或遇到不可到达的代码路径),可以将其返回类型标注为 never

    ts 复制代码
    function throwFn(): never { // ❌ 返回"never"的函数不能有可到达的终点
      console.log('123')
    }
    
    function throwFn(): void {
      console.log('123')
    }
    
    function throwFn(): never {
    	throw new Error("An error occurred.")
    	// 永远不会返回
    }
  2. 在联合类型中,never会被移除,void不会

    ts 复制代码
    type A = number | void | never
    
    type A = number | void

关键区别:

  • void 类型表示函数没有返回值或变量没有明确的值。
  • never 类型表示某些情况下函数永远不会返回或出现不可到达的代码路径。

数组(Array)

定义

数组定义有两种方式,第一种,可以在元素类型后面接上阔号Type[],表示由此类型元素组成的一个数组:

ts 复制代码
let list: number[] = [1, 2, 3];

第二种方式是使用数组泛型,Array<Type>

ts 复制代码
let list: Array<string> = ['1', '2', '3'];

多类型数组

数组中每一项的类型都不一样

ts 复制代码
// 简单粗暴 any
let list: ayn[] = ['泰裤辣', 666, true]

// 使用元组类型
let list2: [string, number, boolean] = ['泰裤辣', 666, true]

对象数组

定义对象类型数组可以使用interface

ts 复制代码
interface Person {
  name: string;
  age: number;
  email: string;
}

// 声明对象数组
const people: Person[] = [
  { name: "Alice", age: 25, email: "alice@example.com" },
  { name: "Bob", age: 30, email: "bob@example.com" },
  { name: "Charlie", age: 35, email: "charlie@example.com" }
];

多维数组

数组里面套数组该如何定义呢

ts 复制代码
let list: number[][] = [[1],[2],[3]]

// or

let list2: Array<Array<number>> = [[1],[2],[3]]

类数组

argumentsc参数是一个类数组和数组类似,但不具备数组相应的方法,这种就不能用普通的方式定义。

ts 复制代码
function say() {
    let arg: any[] = arguments // ❌'arg' is declared but its value is never read.

    let arg2: IArguments = arguments
}

元组类型(Tuples)

元组(Tuples)类型是 TypeScript 中用于表示具有固定数量和特定顺序的不同类型的值的数据结构。

元组是固定数量的不同类型的元素组合,和数组不同的是它的元素类型是不固定,而数量固定。

ts 复制代码
let arr: [string, number, boolean];
arr = ["a", 2, false]; // ✅
arr = [2, "a", false]; // ❌ 不能将类型"number"分配给类型"string"。 不能将类型"string"分配给类型"number"。
arr = ["a", 2];        // ❌ Property '2' is missing in type '[string, number]' but required in type '[string, number, boolean]'
arr[1] = 996

元组定义的数组元素个数都是确定的,类型也固定,当给arr赋值时,要保证各个位置上的元素类型对应。

接口(Interfaces)

定义

interface接口,接口是一种用于描述对象的结构和行为的 TypeScript 抽象类型,它可以用来描述较为复杂的数据结构,用接口定义的数据必须要满足约束。

ts 复制代码
interface Person {
  name: string
  age: number
}
// ❌ 类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性。
// 我们接口里面定义了两个参数,但在实现的时候只有一个参数
let person:Person = {
  name: 'zs'
}

// ✅
let person1:Person = {
  name: 'zs',
  age: 18
}

在函数里面使用

ts 复制代码
interface Info {
	name: string
	slogan: string
}

const person = (info: Info):string => {
  return `${info.name} 真的是 ${info.slogan}`
}
person({name:'xg', slogan: '泰裤辣'})

多个同名接口可以重合

ts 复制代码
interface Person {
  name: string
  age: number
}

interface Person {
  sex: boolean
}

// 两个接口Person属性合并起来
let person: Person = {
  name: 'zs',
  age: 18,
  sex: false
}

接口属性

可选属性

接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在,在可选属性名字定义的后面加一个?符号。

ts 复制代码
interface Person {
  name: string
  age: number
  sex?: boolean
}

// sex 属性可传可不传
let person:Person = {
  name: 'zs',
  age: 18
}

任意属性

当接口定义好后,只用到一两个数据,但是其他数据太多不想定义,这个时候就可以用任意属性。这里定义了将新增的属性类型定义为 any 如果修改为 string 接口内所有数据类型都必须为 string,也就是索引签名。

ts 复制代码
interface Person {
  name: string
  age: number
  [propName: string]: any 
}
let person:Person = {
  name: 'zs',
  age: 18,
  sex: false,
  say: (): string => {
    return '泰裤辣'
  }
} 

只读属性

有些时候定义的字段只能在创建的时候赋值,其他的时候不能修改。就像const定义的数据不能修改。

ts 复制代码
interface Person {
  readonly name: string
  age: number
}
let person:Person = {
  name: 'zs',
  age: 18,
}

person1.name = 'xg' // ❌ 无法为"name"赋值,因为它是只读属性

函数类型接口

对象里面通常有函数方法,同样也可以在接口里面定义,在借口里定义的函数参数、返回值,在使用的时候必须按照约束传入。

ts 复制代码
interface Person {
  name: string
  age: number
  say: (slogan: string) => string
}
let person:Person = {
  name: 'zs',
  age: 18,
  say: (slogan) => {
    return `我真的是${slogan}`
  }
} 

person.say(false) // ❌ 类型"boolean"的参数不能赋给类型"string"的参数

person.say('泰裤辣') // ✅

或者这个接口只定义一个函数

ts 复制代码
interface Fn {
	(name: string): number[]
}

const fn: Fn = function(name) {
	return '' // ❌ 不能将类型"() => string"分配给类型"Fn"。
	return [1]
}

接口继承

A接口要继承B接口的属性,可以通过extends关键字继承

ts 复制代码
interface Person extends Person2 {
  name: string
  age: number
}

interface Person2 {
  sex: boolean
}

// 两个接口Person属性合并起来
let person: Person = {
  name: 'zs',
  age: 18,
  sex: false
}

接口合并

当同名接口出现时,它们将合并成一个接口。

ts 复制代码
interface Person {
  name: string
  age: number
}

interface Person {
  sex: boolean
}

// 最后结果会合并
interface Person {
  sex: boolean
  name: string
  age: number
}

object、Object、{}有什么区别

object

object代表所有非值类型的类型,常用于泛型约束

ts 复制代码
let obj1: object = 123 // ❌
let obj2: object = '123' // ❌
let obj3: object = false // ❌
let obj4: object = [] // ✅
let obj5: object = {} // ✅
let obj6: object = () => {} // ✅

Object

Object类型是所有对象 实例的类型,它是在原型链上最顶层,所有值类型引用类型最终都会指向Object,所以它包含所有类型

ts 复制代码
let obj1: Object = 123 // ✅
let obj2: Object = '123' // ✅
let obj3: Object = false // ✅
let obj4: Object = [] // ✅
let obj5: Object = {} // ✅
let obj6: Object = () => {} // ✅

{}

它也是支持所有类型,和Object一样,相当于Object字面量。

枚举(enums)

枚举(enums)是一种用于定义命名常量集合的数据类型。它们允许我们为一组相关的值分配友好的名称,使代码更易于理解和维护。

使用关键字 enum 后跟枚举名来声明一个枚举。

数字枚举

枚举成员默认从 0 开始自增,可以手动指定值或自定义增长规则。

ts 复制代码
// 未定义 从 0 开始
enum Status {
	'已发布',
	'未发布',
	'已失效',
}
console.log(Status) // { '已发布': 0, '未发布': 1, '已失效': 2 }

定义了枚举值, 从当前数值开始自增长。

ts 复制代码
enum Status {
	'已发布' = 1,
	'未发布',
	'已失效',
}
console.log(Status) // { '已发布': 1, '未发布': 2, '已失效': 3 }

一元、二元表达式也可以

ts 复制代码
enum FileAccess {
    // constant members
    None,
    Read    = 1 << 1,
    Write   = 1 << 2,
    ReadWrite  = Read | Write,
    // computed member
    G = "123".length
}
console.log(FileAccess.ReadWrite) // 6

字符串枚举

当然,枚举值也可以是字符串,此时就没有自增长行为,也可以和数字枚举混合使用。

ts 复制代码
enum Status {
	'已发布' = '1',
	'未发布' = '2',
	'已失效' = 0
}

接口枚举

在定义接口时使用枚举值,而在实现接口时枚举值要和定义时保持一致,枚举值对应上就行。

ts 复制代码
enum Status {
	'已发布' = '1',
	'未发布' = '2',
	'已失效' = 0
}

interface Info {
	status: Status.已发布
}

let test: Info = {
	status: Status.已发布
}

let test2: Info = {
	status: Status.已失效 // ❌ 不能将类型"Status.已失效"分配给类型"Status.已发布"。
}

双向映射

生成的代码中,枚举类型被编译成一个对象,它包含双向映射 (name -> value)(value -> name)

ts 复制代码
enum Status {
	'已发布',
	'已失效'= '2'
}
// number 类型
const value1 = Status.已发布
console.log('value', value1) // value 0

const key = Status[value1]
console.log('key', key) // key 已发布

双向映射只对 number 类型生效,字符串无法映射 ,也就是说,枚举值如果是 string是无法进行映射

ts 复制代码
enum Status {
	'已发布',
	'已失效'= '2'
}
// 字符串
const value2 = Status.已失效
console.log('value2', value2) // value2 2

const key2 = Status[value2]
console.log('key2', key2) // key2 undefined

为什么会这样?打印一下Status看一下

ts 复制代码
enum Status {
	'已发布',
	'已失效'= '2'
}

console.log('Status', Status) // Status { '0': '已发布', '已发布': 0, '已失效': '2' }

枚举通过key: value形式生成一个对象,对于number类型会多生成一条数据value: key,所以我们可以通过Status[value]获取到枚举key。而字符串类型没有生成,所以无法通过映射获取。

函数(Function)

定义返回值

ts 复制代码
function add (num1: number, num2: number): number {
  return num1 + num2
}

// 箭头函数
const add = (num1: number, num2: number): number => a + b

// 函数表达式
cosnt add = function (num1: number, num2: number): number {
  return num1 + num2
}
add(1, 2)

可选参数和默认值

使用问号 ? 来表示可选参数,参数可要可不要。

ts 复制代码
function add (num1: number, num2?: number): number { // 严格模式下 num2 会报错 
  return num1 + num2
}
add(1)

默认值,和ES6用法一样

ts 复制代码
function add (num1: number, num2: number = 2): number {
  return num1 + num2
}
add(1)

剩余参数

ES6 中,可以使用 ...rest 的方式获取函数中的剩余参数(rest 参数)

ts 复制代码
function add (num1: number, num2: number=2, ...args: any[]): number {
  return num1 + num2
}

add(1, 3, 4)

args类型是依靠剩余参数类型,如果第二位后面剩余参数是已知的,比如string,就可以改为...args: string[]

函数重载

当函数的参数是多个不同类型,或者返回值不同,就可以使用函数重载。

比如函数 reverse, 输入数字 123 的时候,输出反转的数字 321,输入字符串 'hello' 的时候,输出反转的字符串 'olleh'

ts 复制代码
function reverse(x: number): number
function reverse(x: string): string
function reverse(x: number | string): number | string | void {
  if (typeof x === 'number') {
    return Number(x.toString().split('').reverse().join(''))
  } else if (typeof x === 'string') {
    return x.split('').reverse().join('')
  }
}

类(Class)

TypeScsript拥有和ES6一样的Class语法,在此基础上增加了一些新的用法,不熟悉的可以看一下阮一峰老师教程ECMAScript 6 入门-Class

定义

Class的属性需要先定义后,再赋值,也可以定义默认值

ts 复制代码
class Person {
  name: string;
  slogan: string;
  sex = false; // 默认值
  constructor(name, slogan) {
    this.name = name;
    this.slogan = slogan;
  }
  say(): void {
    console.log(this.name + this.slogan);
  }
}

const p1 = new Person('xg', 123);

修饰符

TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是公共 public私有 private受保护 protected,默认的修饰符尾 public

public

public 公有的,可以在任何地方被访问,不受限制,所有属性方法默认的为 public

ts 复制代码
class Person {
  name: string;
  slogan: string;
  sex = false; // 默认值
  constructor(name, slogan) {
    this.name = name;
    this.slogan = slogan;
  }
  public say(): void {
    console.log(this.name + this.slogan);
  }
}

const p1 = new Person('xg', '泰裤辣');
p1.say(); // xg泰裤辣

private

private 私有的,定义的属性方法只能在内部访问,就不能在声明它的类的外部访问,通过 extends 关键字继承的子类中也不可以使用。

ts 复制代码
class Person {
  private name: string;
  slogan: string;
  sex = false; // 默认值
  constructor(name, slogan) {
    this.name = name;
    this.slogan = slogan;
  }
  public say(): void {
    console.log(this.name + this.slogan);
  }
}

// 继承 Person  子类中无法访问 private
class Singer extends Person {
  constructor(name, age) {
    super(name, age);
  }
  getPerson(): void {
    console.log('name', this.name); // ❌  属性"name"为私有属性,只能在类"Person"中访问。
  }
}

const p1 = new Person('xg', 123);
console.log('name', p1.name); // ❌ 属性"name"为私有属性,只能在类"Person"中访问。

protected

protected 受保护的,和 private 类似,但有一点不同 protected 可以在继承的子类中使用

ts 复制代码
class Person {
  private name: string;
  slogan: string;
  protected sex = false; // 默认值
  constructor(name, slogan) {
    this.name = name;
    this.slogan = slogan;
  }
  public say(): void {
    console.log(this.name + this.slogan);
  }
}

// 继承 Person  父类中 sex 属性可以在子类中访问 但无法在外界使用
class Singer extends Person {
  constructor(name, age) {
    super(name, age);
  }
  getPerson(): void {
	  // 不可以访问 private
    console.log('name', this.name);
  }
  getSex(): void {
	  // 可以访问 protected
    console.log('sex', this.sex);
  }
}

const p1 = new Person('xg', '泰裤辣');
p1.say(); // xg泰裤辣

const p2 = new Singer('ly', '再靠近我一点');
p2.getSex(); // sex false

// 类的外面访问 protected 属性
p2.sex; // ❌ 属性"sex"受保护,只能在类"Person"及其子类中访问。

readonly修饰符

readonly 将属性设置为只读的,只读属性必须在声明时或构造函数里被初始化,并不能在外界修改,只允许出现在属性声明或索引签名或构造函数中

ts 复制代码
class Person {
  private name: string;
  slogan: string;
  protected sex = false; // 默认值
  readonly id = 1; // 只读属性
  constructor(name, slogan) {
    this.name = name;
    this.slogan = slogan;
  }
  public say(): void {
    // readonly可以访问
    console.log('id', this.id); // id 1
    console.log(this.name + this.slogan);
  }
  
  readonly sing(): void { // ❌ "readonly" 修饰符仅可出现在属性声明或索引签名中。
    console.log(this.name + '在唱歌');
  }
}


const p1 = new Person('xg', '泰裤辣');
console.log('p1.id', p1.id); // 1.id 1
p1.id = '2'; // ❌ 无法为"id"赋值,因为它是只读属性。

注意 如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面。

ts 复制代码
class Person {
  private readonly name: string;
  slogan: string;
  sex = false; // 默认值
  id = 1;
  constructor(name, slogan) {
    this.name = name;
    this.slogan = slogan;
  }

}

存取器

TypeScript支持通过getters/setters来截取对对象成员的访问,可以改变属性的赋值和读取行为。

ts 复制代码
class Person {

  constructor(name) {
    this.name = name; // 这里有一次赋值 也会触发 setter 也就是 set name 方法
  }

  get name(): string {
    return 'return name';
  }

  set name(value: string) {
	  // 执行两次  一次在 constructor 里赋值 一次在外面 p1.name = '234'
	  // set name xg
		// set name 234
    console.log('set name', value);
  }
}

const p1 = new Person('xg');
p1.name = '234';
console.log('get p1.name', p1.name); // get p1.name return name

static 静态属性和静态方法

static 修饰符定义的属性方法,不可以通过 this 取访问,只能通过类名去调用,不需要实例化。

ts 复制代码
class Person {
  static id = '123';
  constructor() {
    this.say(); // ❌ 属性"say"在类型"Person"上不存在。你的意思是改为访问静态成员"Person.say"吗?
  }
  static say(slogan): void {
    console.log(slogan);
    console.log('id', Person.id); // id 123
  }
}
Person.say('泰裤辣'); // 泰裤辣
console.log('Person.id', Person.id); // Person.id 123

抽象类

使用abstract关键字定义类为抽象类,定义的方法都是抽象方法。

  • 抽象方法不能实现,只能定义描述,类似接口一样。
  • 抽象类不能直接杯实例化。它的实例化是毫无意义的,只能基于派生类中去实现。当抽象类中有抽象方法时,必须要实现

抽象类(Abstract Classes):它是一种不能直接实例化的类,只能被继承。

ts 复制代码
abstract class Person {
	name: string
}

const p1 = new Person(); // ❌ 无法创建抽象类的实例

在派生类中实现抽象类

ts 复制代码
abstract class Person {
  name: string;
  constructor(name?: string) {
    this.name = name;
  }
  getName(): string {
    return this.name;
  }

  // 抽象方法
  abstract init(name: string): void;
}

class User extends Person {
  constructor() {
    super();
  }

  init(name: string): void {
    this.name = name;
  }
}

const u1 = new User();
u1.init('xg');
console.log('getName', u1.getName()); // getName xg

类实现接口

以通过 implements 关键字来实现接口,强制类遵循接口的契约。可以使用关键字implements后面跟多个interface的名字,用逗号隔开。

ts 复制代码
interface Person1 {
  name: string;
}
interface Person2 {
  age: number;
}

interface Person3 {
  say: (slogan: string) => void;
}

class Person implements Person1, Person2, Person3 {
  age: number;
  name: string;

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

  say(slogan) {
    console.log(this.name + slogan);
  }
}
const p1 = new Person('xg', 18);
p1.say('泰裤辣');

命名空间(NameSpace)

Namespace用于组织和管理代码,防止全局命名冲突,如果两个模块名称相同,就会报错。

TypeScriptJavaScript一样,都是使用ES5模块,也就是通过export import形式进行导入导出。任何一个包含顶级export import的文件都会当成一个模块,相反,如果一个文件不带顶级export import声明,也会被视为全局可见的模块。

使用关键字 namespace 来声明一个命名空间。,将数据包裹到一个命名空间内,而不是放在全局下。 使用 export 关键字将命名空间中的成员(变量、函数、类等)导出,使其可以在外部访问。

ts 复制代码
// file1.ts
namespace A {
  export const a = 1
}

// file2.ts
namespace B {
  export const a = 2
} 

最后的编译结果就是将命名空间A变成一个对象,导出的数据就为A下面的属性。

ts 复制代码
var A;
(function (A) {
    A.a = 2;
})(A || (A = {}));
console.log('A', A.a);

命名空间可以使用 /// <reference> 指令或模块化的导入语法来使用命名空间中的成员。

ts 复制代码
/// <reference path="file1.ts.ts" />

console.log(A.a)

嵌套命名空间

命名空间可以嵌套在其他命名空间内部,形成层级结构,以更好地组织和管理代码。

ts 复制代码
namespace A {
  export namespace B {
    export const a = 2
  }
} 

import TMP = A.B
console.log('B', A.B.a ) // B 2
console.log('TMP',TMP.a )  // TMP { a: 2 }

合并

命名空间也可以像接口那样合并

ts 复制代码
namespace A {
  export const a = 1
}

namespace A { 
  export const b = 2
}

console.log('A.b', A.b) // A.b 2

TypeScript 进阶

类型注解和类型推断

TypeScript 中,类型注解(Type Annotation)和类型推断(Type Inference)是用来确定变量、函数和表达式的类型的两种方法。

类型注解

类型注解是明确地给变量、函数参数、函数返回值或表达式指定类型的方式。使用 : 后跟类型名称来注解。

ts 复制代码
let age: number = 30;
function greet(name: string): string {
  return "Hello, " + name;
}

在上述示例中,age 被注解为 number 类型,name 参数被注解为 string 类型,函数 greet 的返回值被注解为 string 类型。

类型推断

类型推断是 TypeScript 的一种功能,根据变量的赋值表达式自动推断出变量的类型。TypeScript 根据上下文和赋值的类型推断出变量的类型,而无需显式注解。

在上面例子中,str被推断为string类型,所以在修改的时候不能赋值为其他类型,只能是string

如果声明了变量,但是没有任何赋值、定义类型操作,默认的为any类型

泛型(Generics)

当数据类型不是固定的时候,可以使用泛型将数据类型变成动态的。也就是先不定义数据的一个具体类型,当使用的时候再指定。

函数里的泛型

在函数名后面跟<T>,其中T就是动态的类型,形参value的类型也就是T,返回的也是一个T类型的数组。

当调用函数的时候,在函数名后面传入需要定义的数据类型<string>,此时函数内部所有T都会被替换成string

泛型可以定义多个

ts 复制代码
function getData<T, K>(value1: T,value2: K): Array<T | K> {
  return [value1, value2]
}
getData(1, 2)

getData<string, number>("3", 4)

getData(true, null)

这里没有写,应为通过类型推断,已经知道了类型。

泛型接口

interface或者type中也是可以使用泛型,用法一样。

ts 复制代码
interface ResData<T>{ 
  code: number,
  msg: string
  data: T
}

const response: ResData<boolean> = {
  code: 1,
  msg: 'success',
  data: false
}

type Data<K> = number | string | K

const data: Data<null> = null

泛型变量

看别人的ts代码会看到很多泛型T、E、V...之类的变量,为什么有的地方是T,有的地方是V。TypeScript在这方面没有强制要求,都是开发者们为了方便阅读理解,默认形成的一套规范。

常用的单个字母泛型变量:

  • T:表示一般的泛型类型参数。
  • K:表示对象中的键类型。
  • V:表示对象中的值类型。
  • E:表示数组或元组中的元素类型。
  • R:表示函数的返回类型。
  • S, U, V, ...:表示额外的泛型类型参数。

泛型约束

在函数内部使用泛型时,还不知道是什么类型,也就不能使用操作数据的属性或方法。

ts 复制代码
function test<T>(name: T): void {
  console.log('name length', name.length) // ❌ 类型"T"上不存在属性"length"。
}

此时就可以使用泛型约束,对使用的泛型数据进行约束,约束为具有length属性的类型,如stringArray

语法:< T extends 类型 >

ts 复制代码
interface Len {
  length: number
}

function test<T extends Len>(name: T): void {
  console.log('name length', name.length)
}

test('1')
test([1,2,3])

test(2) // ❌ 类型"number"的参数不能赋给类型"Len"的参数
test(false) // ❌ 类型"boolean"的参数不能赋给类型"Len"的参数。

高级类型

交叉类型

多种类型的集合,使用&符号,联合对象将具有所有联合类型的所有成员,类似接口继承和接口合并。

ts 复制代码
interface Person  {
  name: string
  age: number
}

interface Person2 {
  sex: boolean
}

let person: Person & Person2 = {
  name: 'zs',
  age: 18,
  sex: false
}

联合类型

当数据有多个类型时可以使用

ts 复制代码
let id: string | number 
id = 123
id = '123'
id = false // ❌ 不能将类型"boolean"分配给类型"string | number"

使用联合类型的属性,只能访问此联合类型的所有类型里共有的属性或方法

ts 复制代码
let id: string | number 
id = '123'
id = 123
id.length // ❌ 类型"number"上不存在属性"length"

索引签名

当类型的属性的实际名称是未知的,数据类型也是未知的,就可以使用索引签名。索引签名一般用来新增数据。

ts 复制代码
type User = {
	name: string
	[key: string]: any  // 索引签名
}

const user: User ={
	name: 'xg',
	age: 12
}

需要注意的是索引签名中定义好了数据的类型,必须要和新增的数据类型对应上。

ts 复制代码
interface User {
	name: string
	[key: string]: string  // 索引签名
}

const user: User ={
	name: 'xg',
	age: 12 // ❌ 不能将类型"number"分配给类型"string"
}

keyof 和 typeof

keyof

keyofTypeScript 中的一个操作符,用于获取对象类型或接口类型的键集合。它返回一个联合类型,包含给定类型中所有可用的键。

ts 复制代码
type Person = {
  name: string;
  age: number;
  address: string;
};

type PersonKeys = keyof Person; // "name" | "age" | "address"

keyof类型约束

可以使用 keyof 来约束函数参数或泛型类型参数,以确保传入的值是给定类型的有效键。

ts 复制代码
function getProperty(obj: any, key: keyof typeof obj) {
  return obj[key];
}

const person = {
  name: "John",
  age: 30,
  address: "123 Street",
};

const name = getProperty(person, "name"); // 类型推断为 string

typeof

typeof 操作符用于获取一个值的类型。它允许我们在编译时获取一个值的类型信息,以便进行类型推断、类型声明或类型操作。

ts 复制代码
const p = {
  name: 'CJ',
  age: 18
};

type Person = typeof p;

// 等同于
type Person = {
  name: string;
  age: number;
}

keyof和typeof一起使用

keyoftypeof 可以结合使用,以实现更复杂的类型操作和类型推断。

比如要获取某个对象的key作为类型,可以先通过typeof获取到这个对象的类型,再通过keyofkey设为类型。

ts 复制代码
const person = {
  name: 'xg',
  age: 18,
}

type personType = keyof typeof person  // type personType = "name" | "age"

let p1: personType
p1 = 'name' // ✅
p1 = 'age' // ✅
p1 = 'sex' // ❌ 不能将类型""sex""分配给类型""name" | "age""。

同理,也可以用来规范某个枚举对象的key

ts 复制代码
enum MsgEnum {
  'success' = '请求成功',
  'error' = '请求失败',
  'warring' = '请重试',
}

type msgType = keyof typeof MsgEnum  // type msgType = "success" | "error" | "warring"

let msg: msgType
msg = 'success' // ✅
msg = 'error' // ✅
msg = 'test' // ❌ 不能将类型""test""分配给类型""success" | "error" | "warring""。

类型保护

类型保护是一种在 TypeScript 中确定变量类型的机制,以便在编程过程中执行相应的类型操作。通过类型保护,可以在代码中根据条件判断来缩小变量的类型范围,以便进行更精确的类型操作。

typeof类型保护

使用 typeof 关键字可以进行类型保护,根据变量的类型进行条件判断。

ts 复制代码
function printValue(value: string | number) {
  if (typeof value === "string") {
    console.log(value.toUpperCase());
  } else {
    console.log(value.toFixed(2));
  }
}

注意事项:

  • typeof 类型保护只能用于进行基本类型的判断,如 stringnumberboolean 等。
  • 对于复杂类型,如对象、数组等,typeof 类型保护无法进行精确判断。

instanceof 类型保护:

使用 instanceof 关键字可以进行类型保护,检查对象是否属于特定的类或构造函数。

ts 复制代码
class Person {
  // ...
}

class Animal {
  // ...
}

function printName(obj: Person | Animal) {
  if (obj instanceof Person) {
    console.log(obj.name);
  } else {
    console.log(obj.species);
  }
}

自定义类型保护函数

可以编写自定义的类型保护函数,根据特定的条件判断来确定变量的类型。

ts 复制代码
function isString(value: unknown): value is string {
  return typeof value === "string";
}

function printLength(value: unknown) {
  if (isString(value)) {
    console.log(value.length);
  }
}

类型别名(type)

类型别名是为现有类型创建一个新名字 ,可以通过关键字 type 来定义。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,交叉类型,元组以及其它任何你需要手写的类型。

ts 复制代码
type type1 = string // 原始类型
type type2 = number
type type3 = (name: string) => number // 函数
type type4 = string | type3 // 联合类型
type type5 = string & boolean // 交叉类型
type type6 = [number] // 数组

const str: type1 = '123'

const idCard: type4 = '111111'

type和interface的区别

  1. type无法使用extends关键词继承其他typeinterface可以,只能使用&交叉类型和在一起。
  2. interface遇到重名的会进行合并,type不会。

高级用法

使用extends关键字,左边值会遵循右边值的子类型,可以用三元表达式来判断,决定它最后的类型。

看个例子理解一下,最后type1的类型为boolean

ts 复制代码
type type1 =  string extends any ? string : number // type type1 = boolean

同理,我们可以吧extends右边值换成其他的,猜一下type2最后的类型。

ts 复制代码
type type2 = 1 extends never ? number : string // type type2 = string

它的判断规则遵循TypeScript数据类型的包含关系

  • 顶级类型anyunknown,其他所有类型都是他们的子类。
  • Object类型是所有对象实例的类型,所有类型的原型链顶端都指向它
  • NumberStringBoolean等这些,都是包装类型,在Js中也存在
  • numberstringboolean TypeScript提供的原始类型
  • 1'123'false都是字面量
  • never 底层类型

类型断言(Type Assertion)

类型断言是 TypeScript 中的一种语法,用于告诉编译器某个值的具体类型。可以用来手动指定一个值的类型,就像类型转换,将某个值强制转换为特定类型。

语法:

  • 值 as 类型 value as number
  • <类型>值
ts 复制代码
function fn(value: string | number): number {
	return (value as string).length
}

fn(123123)

注意事项

  • 类型断言是告诉编译器的一种方式,它在编译时起作用,不会影响运行时的类型。
  • 需要注意的是,使用类型断言时要确保断言的类型是正确的,否则可能会导致运行时错误。
  • 如果无法确定断言的类型是否正确,可以使用类型保护机制来进行更安全的类型判断。

symbol类型

ES5中添加了一个新的原始类型symbol,通过它定义的数据是不可改变且唯一的 。创建方式通过Symbol构造函数创建的。

定义

ts 复制代码
let sym1 = Symbol()
let sym2 = Symbol('key') // 可选字符

唯一的

ts 复制代码
let sym1 = Symbol()
let sym2 = Symbol() 
sym1 === sym2 // false

作为对象的key

像字符串一样,symbol也可以被用做对象属性的键。由于symbol的唯一性,在对象里使用symbols作为key也是唯一的,避免属性key重复问题。

ts 复制代码
let sym = Symbol()

let obj = {
	name: 'xg'
	[sym]: 123
}

那如何获取对象中用symbol定义的key呢,普通的对象方法都获取不到,可以使用Reflect.ownKeys()方法。

ts 复制代码
let sym = Symbol()

let obj = {
	name: 'xg',
	[sym]: 123
}

console.log( Reflect.ownKeys(obj)) // [ 'name', Symbol() ]

遍历对象中的Symbol

只遍历symbol

要遍历对象中的 Symbol 属性,可以使用 Object.getOwnPropertySymbols() 方法。该方法返回一个包含对象所有 Symbol 属性的数组。使用遍历循环或其他迭代方法来处理这个数组。【Object.getOwnPropertySymbols() 方法仅返回对象自身的 Symbol 属性,不包括继承的属性。】

ts 复制代码
const name = Symbol('name')
const age = Symbol('age')

const person = {
  [name]: 'xg',
  [age]: 18,
  sex: false,
}

// 获取对象中的所有 Symbol 属性
const symbols = Object.getOwnPropertySymbols(person)
console.log('symbols', symbols) // symbols [ Symbol(name), Symbol(age) ]

// 遍历 Symbol 属性数组
symbols.forEach((symbol) => {
  console.log(symbol, person[symbol])
  // Symbol(name) xg
  // Symbol(age) 18
})

遍历所有key

如果需要同时遍历对象的 Symbol 属性和其他属性,您可以使用 Reflect.ownKeys() 方法。该方法返回一个包含对象所有属性(包括 Symbol 和非 Symbol 属性)的数组。

ts 复制代码
const name = Symbol('name')
const age = Symbol('age')

const person = {
  [name]: 'xg',
  [age]: 18,
  sex: false,
}
// 获取对象中的所有属性(包括 Symbol 和非 Symbol 属性)
const keys = Reflect.ownKeys(person)
console.log('keys', keys) // keys [ 'sex', Symbol(name), Symbol(age) ]

// 遍历所有属性
keys.forEach((key) => {
  console.log(key, person[key])
  // sex false
  // Symbol(name) xg
  // Symbol(age) 18
})

三斜杠指令

三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。三斜线指令仅可放在包含它的文件的最顶端

三斜线引用告诉编译器在编译过程中要引入的额外的文件,会将依赖的文件编译到同一个文件当中。

如果在tsconfig.json中指定了noResolve: true,就会忽略三斜线指令。

导入声明文件

语法:/// <reference path="..." />node types文件里,引入了各种模块的声明文件

ts 复制代码
/// <reference path="http.d.ts" />
/// <reference path="http2.d.ts" />
/// <reference path="https.d.ts" />

导入第三方包

语法:/// <reference types="node" /> 比如导入一下node的数据类型,先安装一下npm i @type/node -D

ts 复制代码
/// <reference types="node"/>

声明文件.d.ts

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

有些三方库内部已经有了,可以直接使用,如果没有就需要另外安装。

比如express库,源码里面是没有声明文件,所有要安装对应的声明文件

bash 复制代码
npm i --save-dev @types/express

三方声明文件安装规则,都是以@type/开头,后面接库的名称,也可以在npm types上搜索对应的声明文件。

如果三方声明文件库都没有,就要手动书写声明文件,文件后缀名为.d.ts declare关键字可以将定义的类型暴露出来

ts 复制代码
declare var 声明全局变量
declare function 声明全局方法
declare class 声明全局类
declare enum 声明全局枚举类型
declare namespace 声明(含有子属性的)全局对象
interface 和 type 声明全局类型

配置文件详解

创建TypeScript配置文件tsconfig.json,添加 --locale zh-CN参数生产的文件注释都是中文

bash 复制代码
tsc --init --locale zh-CN
json 复制代码
{
  "compilerOptions": {
    /* 请访问 https://aka.ms/tsconfig,了解有关此文件的详细信息 */

    /* 项目 */
    // "incremental": true,                              /* 保存 .tsbuildinfo 文件以允许项目增量编译。 */
    // "composite": true,                                /* 启用允许将 TypeScript 项目与项目引用一起使用的约束。 */
    // "tsBuildInfoFile": "./.tsbuildinfo",              /* 指定 .tsbuildinfo 增量编译文件的路径。 */
    // "disableSourceOfProjectReferenceRedirect": true,  /* 在引用复合项目时禁用首选源文件而不是声明文件。 */
    // "disableSolutionSearching": true,                 /* 在编辑时选择项目退出多项目引用检查。 */
    // "disableReferencedProjectLoad": true,             /* 减少 TypeScript 自动加载的项目数。 */

    /* 语言和环境 */
    "target": "es2016",                                  /* 为发出的 JavaScript 设置 JavaScript 语言版本并包含兼容的库声明。 */
    // "lib": [],                                        /* 指定一组描述目标运行时环境的捆绑库声明文件。 */
    // "jsx": "preserve",                                /* 指定生成的 JSX 代码。 */
    // "experimentalDecorators": true,                   /* Enable experimental support for legacy experimental decorators. */
    // "emitDecoratorMetadata": true,                    /* 为源文件中的修饰声明发出设计类型元数据。 */
    // "jsxFactory": "",                                 /* 指定在将 React JSX 发出设定为目标时要使用的 JSX 中心函数,例如 "react.createElement" 或 "h"。 */
    // "jsxFragmentFactory": "",                         /* 指定在将 React JSX 发出设定为目标时用于片段的 JSX 片段引用,例如 "React.Fragment" 或 "Fragment"。 */
    // "jsxImportSource": "",                            /* 指定使用 "jsx: react-jsx*" 时用于导入 JSX 中心函数的模块说明符。 */
    // "reactNamespace": "",                             /* 指定为 "createElement" 调用的对象。这仅适用于将 "react" JSX 发出设定为目标的情况。 */
    // "noLib": true,                                    /* 禁用包括任何库文件(包括默认的 lib.d.ts)。 */
    // "useDefineForClassFields": true,                  /* 发出符合 ECMAScript 标准的类字段。 */
    // "moduleDetection": "auto",                        /* 控制用于检测模块格式 JS 文件的方法。 */

    /* 模块 */
    "module": "commonjs",                                /* 指定生成的模块代码。 */
    // "rootDir": "./",                                  /* 指定源文件中的根文件夹。 */
    // "moduleResolution": "node10",                     /* 指定 TypeScript 如何从给定的模块说明符查找文件。 */
    // "baseUrl": "./",                                  /* 指定基目录以解析非相关模块名称。 */
    // "paths": {},                                      /* 指定一组将导入重新映射到其他查找位置的条目。 */
    // "rootDirs": [],                                   /* 允许在解析模块时将多个文件夹视为一个文件夹。 */
    // "typeRoots": [],                                  /* 指定多个行为类似于 "./node_modules/@types" 的文件夹。 */
    // "types": [],                                      /* 指定要包含的类型包名称,而无需在源文件中引用。 */
    // "allowUmdGlobalAccess": true,                     /* 允许从模块访问 UMD 变量全局。 */
    // "moduleSuffixes": [],                             /* 解析模块时要搜索的文件名后缀列表。 */
    // "allowImportingTsExtensions": true,               /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
    // "resolvePackageJsonExports": true,                /* Use the package.json 'exports' field when resolving package imports. */
    // "resolvePackageJsonImports": true,                /* Use the package.json 'imports' field when resolving imports. */
    // "customConditions": [],                           /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
    // "resolveJsonModule": true,                        /* 启用导入 .json 文件。 */
    // "allowArbitraryExtensions": true,                 /* Enable importing files with any extension, provided a declaration file is present. */
    // "noResolve": true,                                /* 禁止 "import"、"require" 或 "<reference>" 扩展 TypeScript 应添加到项目的文件数。 */

    /* JavaScript 支持 */
    // "allowJs": true,                                  /* 允许 JavaScript 文件成为程序的一部分。使用 "checkJS" 选项从这些文件中获取错误。 */
    // "checkJs": true,                                  /* 在已检查类型的 JavaScript 文件中启用错误报告。 */
    // "maxNodeModuleJsDepth": 1,                        /* 指定用于从 "node_modules" 检查 JavaScript 文件的最大文件夹深度。仅适用于 "allowJs"。 */

    /* 发出 */
    // "declaration": true,                              /* 从项目的 TypeScript 和 JavaScript 文件生成 .d.ts 文件。 */
    // "declarationMap": true,                           /* 为 d.ts 文件创建源映射。 */
    // "emitDeclarationOnly": true,                      /* 仅输出 d.ts 文件,而不输出 JavaScript 文件。 */
    // "sourceMap": true,                                /* 为发出的 JavaScript 文件创建源映射文件。 */
    // "inlineSourceMap": true,                          /* 在发出的 JavaScript 中包括源映射文件。 */
    // "outFile": "./",                                  /* 指定将所有输出捆绑到一个 JavaScript 文件中的文件。如果 "declaration" 为 true,还要指定一个捆绑所有 .d.ts 输出的文件。 */
    // "outDir": "./",                                   /* 为所有已发出的文件指定输出文件夹。 */
    // "removeComments": true,                           /* 禁用发出注释。 */
    // "noEmit": true,                                   /* 禁用从编译发出文件。 */
    // "importHelpers": true,                            /* 允许每个项目从 tslib 导入帮助程序函数一次,而不是将它们包含在每个文件中。 */
    // "importsNotUsedAsValues": "remove",               /* 指定仅用于类型的导入的发出/检查行为。 */
    // "downlevelIteration": true,                       /* 发出更合规但更详细且性能较低的 JavaScript 进行迭代。 */
    // "sourceRoot": "",                                 /* 指定调试程序的根路径以查找引用源代码。 */
    // "mapRoot": "",                                    /* 指定调试程序应将映射文件放置到的位置而不是生成的位置。 */
    // "inlineSources": true,                            /* 在发出的 JavaScript 内的源映射中包含源代码。 */
    // "emitBOM": true,                                  /* 在输出文件的开头发出一个 UTF-8 字节顺序标记(BOM)。 */
    // "newLine": "crlf",                                /* 设置发出文件的换行符。 */
    // "stripInternal": true,                            /* 禁用在其 JSDoc 注释中包含 "@internal" 的发出声明。 */
    // "noEmitHelpers": true,                            /* 在已编译输出中禁用生成自定义帮助程序函数(如 "__extends")。 */
    // "noEmitOnError": true,                            /* 禁用在报告了任何类型检查错误时发出文件。 */
    // "preserveConstEnums": true,                       /* 在生成的代码中禁用擦除 "const enum" 声明。 */
    // "declarationDir": "./",                           /* 指定已生成声明文件的输出目录。 */
    // "preserveValueImports": true,                     /* 保留 JavaScript 输出中未使用的导入值,否则将删除这些值。 */

    /* 互操作约束 */
    // "isolatedModules": true,                          /* 确保可以安全地转译每个文件,而无需依赖其他导入。 */
    // "verbatimModuleSyntax": true,                     /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
    // "allowSyntheticDefaultImports": true,             /* 当模块没有默认导出时,允许"从 y 导入 x"。 */
    "esModuleInterop": true,                             /* 发出其他 JavaScript 以轻松支持导入 CommonJS 模块。这将启用 "allowSyntheticDefaultImports" 以实现类型兼容性。 */
    // "preserveSymlinks": true,                         /* 禁用将符号链接解析为其实际路径。这会关联到节点中的同一标志。 */
    "forceConsistentCasingInFileNames": true,            /* 确保导入中的大小写正确。 */

    /* 类型检查 */
    "strict": true,                                      /* 启用所有严格类型检查选项。 */
    // "noImplicitAny": true,                            /* 对具有隐式 "any" 类型的表达式和声明启用错误报告。 */
    // "strictNullChecks": true,                         /* 进行类型检查时,请考虑 "null" 和 "undefined"。 */
    // "strictFunctionTypes": true,                      /* 分配函数时,请检查以确保参数和返回值与子类型兼容。 */
    // "strictBindCallApply": true,                      /* 检查 "bind"、"call" 和 "apply" 方法的参数是否与原始函数匹配。 */
    // "strictPropertyInitialization": true,             /* 检查是否有已声明但未在构造函数中设置的类属性。 */
    // "noImplicitThis": true,                           /* 在 "this" 的类型为 "any" 时启用错误报告。 */
    // "useUnknownInCatchVariables": true,               /* 将 catch 子句变量默认为 "unknown" 而不是 "any"。 */
    // "alwaysStrict": true,                             /* 请确保始终发出 "se strict"。 */
    // "noUnusedLocals": true,                           /* 在未读取局部变量时启用错误报告。 */
    // "noUnusedParameters": true,                       /* 在未读取函数参数时引发错误。 */
    // "exactOptionalPropertyTypes": true,               /* 将可选属性类型解释为已写,而不是添加 "undefined"。 */
    // "noImplicitReturns": true,                        /* 为未在函数中显式返回的代码路径启用错误报告。 */
    // "noFallthroughCasesInSwitch": true,               /* 为 switch 语句中的故障案例启用错误报告。 */
    // "noUncheckedIndexedAccess": true,                 /* 使用索引访问时,将 "undefined" 添加到类型。 */
    // "noImplicitOverride": true,                       /* 确保使用替代修饰符标记派生类中的替代成员。 */
    // "noPropertyAccessFromIndexSignature": true,       /* 对使用索引类型声明的键强制使用索引访问器。 */
    // "allowUnusedLabels": true,                        /* 对未使用的标签禁用错误报告。 */
    // "allowUnreachableCode": true,                     /* 对无法访问的代码禁用错误报告。 */

    /* 完成度 */
    // "skipDefaultLibCheck": true,                      /* 跳过 TypeScript 附带的类型检查 .d.ts 文件。 */
    "skipLibCheck": true                                 /* 跳过对所有 .d.ts 文件的类型检查。 */
  },
  "include": ["src/**/*.ts", "demo.ts"] ,                /* 指定包含的目录、文件*/
  "exclude": ["test.ts"],                                /* 排除的目录、文件*/
}

相关文档

持续更新中....

相关推荐
foxhuli22937 分钟前
禁止ifrmare标签上的文件,实现自动下载功能,并且隐藏工具栏
前端
青皮桔1 小时前
CSS实现百分比水柱图
前端·css
失落的多巴胺1 小时前
使用deepseek制作“喝什么奶茶”随机抽签小网页
javascript·css·css3·html5
DataGear1 小时前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化
影子信息1 小时前
vue 前端动态导入文件 import.meta.glob
前端·javascript·vue.js
青阳流月1 小时前
1.vue权衡的艺术
前端·vue.js·开源
样子20181 小时前
Vue3 之dialog弹框简单制作
前端·javascript·vue.js·前端框架·ecmascript
kevin_水滴石穿1 小时前
Vue 中报错 TypeError: crypto$2.getRandomValues is not a function
前端·javascript·vue.js
翻滚吧键盘1 小时前
vue文本插值
javascript·vue.js·ecmascript
孤水寒月2 小时前
给自己网站增加一个免费的AI助手,纯HTML
前端·人工智能·html