likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 18

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

前言

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

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

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

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

TypeScript开发环境

安装

全局安装Typescript

npm install -g typescript

// 查看版本
tsc -v

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

tsc --init --locale zh-CN

编译执行

编译ts文件

tsc index.ts

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

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

npm i ts-node -g

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

ts-node index.ts

VsCode插件

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

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

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

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

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

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

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

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

ts文件中效果就是这样

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

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

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

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

现在报错就都是中文

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

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

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

TypeScrtip基础

数据类型

原始数据类型

字符串

使用string定义类型

const str:string = '泰裤辣'

还可以使用模版字符串

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

数字

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

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定义类型

let booleand: boolean = true

空值

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

function say(): void{
	console.log('泰裤辣')
}

void表示undefinednull

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

Null 和 Undefined

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

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

let test: void = undefined
let str: string = '泰裤辣'

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

换成null或者undefined就没问题

let test: null = null
let num: number = 2

num = test

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

{
	"compileroptions": {
		...
		"strict": true
	}
}

any、unknown 、never

any

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

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

let str: any = '泰裤辣'

str = 123
str = true

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

let anys
ayns = 123
ayns = true

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

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

unknown

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

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

let str: unknown = '泰裤辣'
let num: number = 1
let anys: any = false

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

// ✅ 赋值给 any 
anys = str

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

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

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

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

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

never

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

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

type A = string | number | never

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

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

几个例子

// 返回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
    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不会
    type A = number | void | never
    
    type A = number | void
    

关键区别:

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

数组(Array)

定义

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

let list: number[] = [1, 2, 3];

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

let list: Array<string> = ['1', '2', '3'];

多类型数组

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

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

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

对象数组

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

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" }
];

多维数组

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

let list: number[][] = [[1],[2],[3]]

// or

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

类数组

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

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

    let arg2: IArguments = arguments
}

元组类型(Tuples)

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

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

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 抽象类型,它可以用来描述较为复杂的数据结构,用接口定义的数据必须要满足约束。


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

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

在函数里面使用

interface Info {
	name: string
	slogan: string
}

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

多个同名接口可以重合

interface Person {
  name: string
  age: number
}

interface Person {
  sex: boolean
}

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

接口属性

可选属性

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

interface Person {
  name: string
  age: number
  sex?: boolean
}

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

任意属性

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

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

只读属性

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

interface Person {
  readonly name: string
  age: number
}
let person:Person = {
  name: 'zs',
  age: 18,
}

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

函数类型接口

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

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('泰裤辣') // ✅

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

interface Fn {
	(name: string): number[]
}

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

接口继承

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

interface Person extends Person2 {
  name: string
  age: number
}

interface Person2 {
  sex: boolean
}

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

接口合并

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

interface Person {
  name: string
  age: number
}

interface Person {
  sex: boolean
}

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

object、Object、{}有什么区别

object

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

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

Object

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

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 开始自增,可以手动指定值或自定义增长规则。

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

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

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

一元、二元表达式也可以

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

字符串枚举

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

enum Status {
	'已发布' = '1',
	'未发布' = '2',
	'已失效' = 0
}

接口枚举

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

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)

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

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

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

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

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

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

enum Status {
	'已发布',
	'已失效'= '2'
}

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

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

函数(Function)

定义返回值

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)

可选参数和默认值

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

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

默认值,和ES6用法一样

function add (num1: number, num2: number = 2): number {
  return num1 + num2
}
add(1)

剩余参数

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

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'

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的属性需要先定义后,再赋值,也可以定义默认值

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

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 关键字继承的子类中也不可以使用。

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 可以在继承的子类中使用

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

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 和其他访问修饰符同时存在的话,需要写在其后面。

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

}

存取器

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


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 取访问,只能通过类名去调用,不需要实例化。

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):它是一种不能直接实例化的类,只能被继承。

abstract class Person {
	name: string
}

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

在派生类中实现抽象类

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的名字,用逗号隔开。

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声明,也会被视为全局可见的模块。

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

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

// file1.ts
namespace A {
  export const a = 1
}

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

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

var A;
(function (A) {
    A.a = 2;
})(A || (A = {}));
console.log('A', A.a);

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

/// <reference path="file1.ts.ts" />

console.log(A.a)

嵌套命名空间

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

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 }

合并

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

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)是用来确定变量、函数和表达式的类型的两种方法。

类型注解

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

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

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

类型推断

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

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

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

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

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

泛型(Generics)

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

函数里的泛型

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

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

泛型可以定义多个

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)

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

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

泛型接口

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

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, ...:表示额外的泛型类型参数。

泛型约束

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

function test<T>(name: T): void {
  console.log('name length', name.length) // ❌ 类型“T”上不存在属性“length”。
}

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

语法:< T extends 类型 >

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”的参数。

高级类型

交叉类型

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

interface Person  {
  name: string
  age: number
}

interface Person2 {
  sex: boolean
}

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

联合类型

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

let id: string | number 
id = 123
id = '123'
id = false // ❌ 不能将类型“boolean”分配给类型“string | number”

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

let id: string | number 
id = '123'
id = 123
id.length // ❌ 类型“number”上不存在属性“length”

索引签名

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

type User = {
	name: string
	[key: string]: any  // 索引签名
}

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

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

interface User {
	name: string
	[key: string]: string  // 索引签名
}

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

keyof 和 typeof

keyof

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

type Person = {
  name: string;
  age: number;
  address: string;
};

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

keyof类型约束

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

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

const p = {
  name: 'CJ',
  age: 18
};

type Person = typeof p;

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

keyof和typeof一起使用

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

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

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

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 关键字可以进行类型保护,根据变量的类型进行条件判断。

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

注意事项:

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

instanceof 类型保护:

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

class Person {
  // ...
}

class Animal {
  // ...
}

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

自定义类型保护函数

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

function isString(value: unknown): value is string {
  return typeof value === "string";
}

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

类型别名(type)

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

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

type type1 =  string extends any ? string : number // type type1 = boolean

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

type type2 = 1 extends never ? number : string // type type2 = string

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

  • 顶级类型anyunknown,其他所有类型都是他们的子类。
  • Object类型是所有对象实例的类型,所有类型的原型链顶端都指向它
  • NumberStringBoolean等这些,都是包装类型,在Js中也存在
  • numberstringboolean TypeScript提供的原始类型
  • 1'123'false都是字面量
  • never 底层类型 【2w+字笔记】前端的你用得上的TypeScript入门指北🧭

类型断言(Type Assertion)

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

语法:

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

fn(123123)

注意事项

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

symbol类型

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

定义

let sym1 = Symbol()
let sym2 = Symbol('key') // 可选字符

唯一的

let sym1 = Symbol()
let sym2 = Symbol() 
sym1 === sym2 // false

作为对象的key

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

let sym = Symbol()

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

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

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 属性,不包括继承的属性。】

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 属性)的数组。

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文件里,引入了各种模块的声明文件

/// <reference path="http.d.ts" />
/// <reference path="http2.d.ts" />
/// <reference path="https.d.ts" />

导入第三方包

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

/// <reference types="node"/>

声明文件.d.ts

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

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

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

npm i --save-dev @types/express

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

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

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

配置文件详解

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

tsc --init --locale zh-CN
{
  "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"],                                /* 排除的目录、文件*/
}


相关文档

持续更新中....

转载自:https://juejin.cn/post/7272340330698883129
评论
请登录