TypeScript语法总结

JavaScript 与 TypeScript 的区别

TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。

TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
在这里插入图片描述

NPM 安装 TypeScript

如果你的本地环境已经安装了 npm 工具,可以使用以下命令来安装。

使用国内镜像:

npm config set registry https://registry.npmmirror.com

安装 typescript:

npm install -g typescript  # -g 是代表全局安装,不改变环境就使用cnmp命令(前提是已安装)#使用淘宝镜像的命令:
npm install -g cnpm --registry=https://registry.npmmirror.com # cnpm命令安装

如果出现以下错误:
npm err! Error: connect ECONNREFUSED 127.0.0.1:8087
解决办法为:
npm config set proxy null

安装完成后我们可以使用 tsc 命令来执行 TypeScript 的相关代码,以下是查看版本号:

$ tsc -v

Version 5.3.3

在这里插入图片描述

如果安装报错大概率就是权限问题,请使用管理员的命令行模式

然后我们的ts文件是不能够在浏览器当中进行解析的,我们的ts文件首先需要通过编译,编译之后才能够被浏览器进行解析,我们直接使用命令

// tsc + 文件名
tsc demo.ts

编译之后我们的目录下面会产生一个和ts文件同名的js文件,之后我们就可以直接使用这个编译得到的js即可。我们安装好了node,就可以直接使用node命令对js文件进行解析了,使用node命令:

// node + 文件名
node demo.js

安装Visual Studio的TypeScript插件

插件市场安装即可

配置文件

tsc命令不仅仅可以去编译指定某个ts文件,它还可以去编译整个项目,编译整个工程。

创建 TypeScript 配置文件

tsc --init

命令之后,会生成一个 tsconfig.json 文件。
在这里插入图片描述

常用的选项

target:作用就是用设置编译过后 Javascript 所采用的 ECMA 标准;

module:输出的代码采用什么样的方式去进行模块化;

outDir:设置编译结果输出到的文件夹,一般我们会输出到 dist 文件夹;

rootDir:配置我们源代码,也就是 Typescript 的代码所在的文件夹,一般我们会把源代码放在src目录;

sourceMap:开启源代码映射,开启之后,调试的时候可以 sourceMap 文件进行调试源代码;

strict:开启所有严格检查选项,严格模式下,需要我们对每一个成员都要指定明确的类型等等;

需要注意的是,如果我们还是使用 tsc 编译某个 ts文件时,配置文件是不起作用的,只有当我们直接运行tsc命令去编译整个项目时,配置文件才生效。

{/*** 用来指定哪些ts需要被编译 ** 表示任意目录 * 表示任意文件*/"include": ["./"],"exclude": ["./demo.ts"],"compilerOptions": {// 编译的js版本目标"target": "ES6",// 模块化版本"module": "system",// 指定项目中要使用到的库"lib": ["esnext"],// 编译后所在目录"outDir": "./dist",// 将编译的js合并到一起"outFile": "./dist/app.js",// 是否对js进行编译,false表示不对js进行编译"allowJs": false,// 是否对js文件进行检验,false表示不检验"checkJs": false,// 是否移除注释,false表示不去掉注释"removeComments": false,// 不生成编译文件,"noEmit": false,// 当编译出错时不生成编译文件"noEmitOnError": false,// 所有严格模式的总开关"strict": false,// 是否开启严格模式,false表示不开启"alwaysStrict": false,// 当一个变量不指定类型时,默认使用any,设置为true时,表示不允许使用隐式any"noImplicitAny": false,// 设置为true,表示不允许使用隐式this"noImplicitThis": false,}
}

作用域问题

在这里插入图片描述
解决方式一:

  • 用一个立即执行函数创建一个单独的作用域
(function () {const a: string = 'foobar'
})()

解决方式二:

  • 使用export 导出,这样的话这个文件就会作为一个模块导出,模块有单独的模块作用域
const a: string = 'foobar'export {}

注意export后面的{ },是export 的语法,并不是表示导出一个空对象

TypeScript 基础类型分类

原始类型(Primitive Types)

string-字符串number-数字类型boolean-布尔类型
const a: string = 'foobar'const b: number = 100 // 包括NaN Infinityconst c: boolean = true // false

跟 flow 不同,以上这三种类型在非严格模式(strictNullChecks)是允许为空的,也就是说我们可以赋值为 null 或者是 undefined

const a: string = null // undefined
const b: number = null // undefined
const c: boolean = null // undefined

但需要注意的是:在严格模式下是不允许的.

viodnullundefined
const e: void = undefinedconst f: null = nullconst g: undefined = undefined
Symbol

Symbol 是 ES2015 标准中定义的成员,使用它的前提是必须确保有对应的 ES2015 标准库引用,也就是 tsconfig.json 中的 lib 选项必须包含 ES2015 。
配置tsconfig.json

{"compilerOptions": {"lib": ["es2015"]}
}

定义symbol类型

const h: symbol = Symbol()

object 类型(Object Types)

Typescript 中 Object 类型不单是指普通对象类型,它泛指所有的非原始类型,也就是对象,数组还有函数。

// 注意这里的 object 类型首字母是小写的// 函数
const fn: object = function () {}// 普通对象
const obj: object = {}// 数组
const arr: object = []

如果需要普通对象类型,就要使用类似对象字面量的语法去标记类型,这种对象类型限制,它要求我们赋值对象的结果必须要跟我们标记类型的结构完全一致,不能多,也不能少。

const obj: { foo: number, str: string } = { foo: 123, str: '123' }

更好的方式是使用接口的方式,下面会有讲哦。

数组类型(Array Types)

TypeScript 定义数组的方式跟 flow 几乎完全一致。

使用 Array 泛型
// 元素类型选择 number,表示纯数字数组

const arr1: Array<number> = [1, 2, 3]

使用元素类型 + [ ]

// 元素类型选择 number,表示纯数字数组const arr1: number[] = [1, 2 ,3]

元组类型(Tuple Types)

元组就是一个明确元素数量以及每一个元素类型的数组。

定义元组类型的方式:可类似数组字面量

// 这个时候表示:只能存储两个对应类型的元素

const tuple: [number, string] = [18, 'zhangsan']

访问元组当中元素的方式

可以使用数组下标的方式去访问

const tuple: [number, string] = [18, 'zhangsan']const age = tuple[0]
const name = tuple[1]

使用数组解构的方式去提取

const tuple: [number, string] = [18, 'zhangsan']const [age, name] = tuple

元组一般用于一个函数中返回多个返回值

const entries: [string, number][] = Object.entries({foo: 123,bar: 456
})const [key, value] = entries[0]
// key => foo, value => 123

枚举类型(Enum Types)

枚举的介绍
枚举类型的特点

可以给一组数值取上一个更好理解的名字;
一个枚举中只会存在几个固定的值,并不会出现超出范围的可能性;
在很多编程语言中都会有枚举这种数据结构,但是在 JavaScript 中没有这种枚举数据结构,很多时候都是用一个对象来模拟枚举,如下:

const PostStatus = {Draft: 0,Unpublished: 1,Published: 2
}const post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: PostStatus.Draft // 0 // 1 // 2
}

在 Typescript 当中可以用 enum 关键词声明一个枚举,{ } 里面是枚举的值,注意的是用 = 号,使用方式跟对象一样。

enum PostStatus {Draft = 0,Unpublished = 1,Published = 2
}const post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: PostStatus.Draft // 0 // 1 // 2
}
数字枚举

枚举值自动基于前一个值自增,如果没指定具体数值,则从 0 开始。

enum PostStatus1 {Draft, // 0Unpublished, // 1Published // 2
}enum PostStatus2 {Draft = 6, // 6Unpublished, // 7Published2 // 8
}const post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: PostStatus1.Draft // 0 // 1 // 2
}
字符串枚举

字符串枚举无法自增,需要手动添加,字符串枚举不太常见。

enum PostStatus {Draft = 'a',Unpublished = 'b',Published2 = 'c'
}const post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: PostStatus.Draft // a // b // c
}

枚举类型会影响编译结果
枚举类型会入侵到我们的运行时的代码,也就是说它会影响我们编译后的结果,我们在Typescript当中使用大量的大多数类型,经过编译转换过后都会被移除掉,因为它们只是为了我们在编译过程中可以进行类型检查;但是枚举类型不会,它最终会编译成一个双向的键值对对象,目的是可以让我们动态的根据枚举值去或者枚举的名称,也就是说我们可以通过索引器的方式去访问对应的枚举名称。

编译前

enum PostStatus {Draft,Unpublished,Published
}const post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: PostStatus.Draft // 0 // 1 // 2
}

编译后

"use strict";
var PostStatus;
(function (PostStatus) {PostStatus[PostStatus["Draft"] = 0] = "Draft";PostStatus[PostStatus["Unpublished"] = 1] = "Unpublished";PostStatus[PostStatus["Published"] = 2] = "Published";
})(PostStatus || (PostStatus = {}));
var post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: PostStatus.Draft // 0 // 1 // 2
};
常量枚举

如果我们确认我们代码中不会使用索引器的方式去访问枚举,那推荐使用常量枚举,常量枚举:enum 前面加个关键词 const。

编译前

const enum PostStatus {Draft,Unpublished,Published
}const post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: PostStatus.Draft // 0 // 1 // 2
}

编译后

"use strict";
var post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: 0 /* Draft */ // 0 // 1 // 2
};

函数类型(Function Types)

无非是对输入输出做限制,也就是参数和返回值。

函数声明的类型限制

基本用法

function func (a: number, b:number): string {return 'func1'
}func(100, 200)

需要注意,形参和实参的个数要一致

可选参数

  • 在参数后面加一个 ? 号
function func (a: number, b?:number): string {return 'func1'
}func(100)
  • 使用 es6,添加默认参数,因为添加默认值的参数就可有可无。
function func (a: number, b:number = 10): string {return 'func1'
}func(100)

注意:使用可选参数或者是默认参数,都必须要在参数列表的最后.

接收任意个数参数

使用 es6 的 … 操作符.

function func (a: number, ...rest: number[]): string {return 'func1'
}func(100, 200, 300, 400)
函数表达式的类型限制

因为函数表达式最终是放在一个变量上的,接收这个函数的变量,也是应该有类型的.

const func = function (a: number, b: number): string {return 'func1'
}

typescript一般会根据函数表达式推断出这个变量的类型
在这里插入图片描述

如果是把一个函数作为参数传递,也就是回调函数的方式,一般我们就会去约束我们这个回调函数形参的类型,使用类似箭头函数的方式去表示我们这个参数接收什么类型的函数,这种方式在定义接口的时候经常用到。

const func: (a: number, b: number) => string = function (a: number, b: number): string {return 'func1'
}

任意类型(Any Types)

由于 JavaScript 自身是弱类型的关系,很多内置的 API 它本身就支持接收任意类型的参数,而 Typescript 它又是基于 Javascript 的基础之上的,所以说我们难免会在代码当中需要去用一个变量接收任意类型的数据。

// 任意类型(弱类型)
function stringify (value: any) {return JSON.stringify(value)
}stringify('string')stringify(100)stringify(true)// any 类型仍然属于动态类型,它的特点跟普通 JavaScript 变量是一样的
// 也就是可以接收任意类型的值
let foo: any = 'string'// 在运行当中还可以接收其他类型的值
foo = 100foo.bar()// any 类型是不安全的

any 类型,typescript 不会去做类型检查,仍然会存在类型安全的问题。所以不要轻易去使用这种类型。

隐式类型推断

在 Typescript中,如果我们没有通过类型注解去明确一个变量的类型,那么 typescript 会根据变量的使用情况,来推断这个变量的类型,这样一种特性叫隐式类型推断。

定义一个变量赋值一个 number 类型的值,typescript会推断这个变量为 number 类型,如下:
在这里插入图片描述

此时我们在给变量赋值为 string 类型的话就会 typescript 就会报错提示,如下:
在这里插入图片描述
如果 typescript 无法推断变量的类型,就会把它当成 any 类型,如下:
在这里插入图片描述
虽然 Typescript 中支持隐式类型推断,而且这种隐式类型推断可以帮我们简化一部分代码,但仍然建议为每个变量添加明确的类型,方便以后我们能更好理解我们的代码。

类型断言(Type assertions)

有时候在某些特殊情况下,typescript 无法推断变量的具体类型,但是我们作为开发者,根据代码的具体情况,是可以明确知道这个变量的类型的,那么我们可以通过类型断言告诉 typescript 这个变量的类型。
在这里插入图片描述
这种情况我们就可以去断言 res 是个 number 类型。

使用 as 关键词(推荐)

const num1 = res as number

在这里插入图片描述
在变量的前面使用 <类型> 的方式断言
这种方式需要注意的是不能在 jsx 中使用<> 会跟 jsx 中的标签产生语法上的冲突

const num1 = <number>res

在这里插入图片描述

注意:类型断言并不是类型转换,因为类型转换是代码在运行时的概念,而类型断言它只是在编译过程当中的概念,当代码编译过后这个断言就不会存在了,所以它跟类型转换是有本质的差异的。

TypeScript 联合类型

联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。

注意:只能赋值指定的类型,如果赋值其它类型就会报错。

变量联合类型

创建联合类型的语法格式如下:

Type1|Type2|Type3 

实例
声明一个联合类型:

var val:string|number 
val = 12 
console.log("数字为 "+ val) 
val = "Runoob" 
console.log("字符串为 " + val)

也可以将联合类型作为函数参数使用

function disp(name:string|string[])
function disp(name:string|string[]) { if(typeof name == "string") { console.log(name) } else { var i; for(i = 0;i<name.length;i++) { console.log(name[i])} } 
} 
disp("Runoob") 
console.log("输出数组....") 
disp(["Runoob","Google","Taobao","Facebook"])

联合类型数组

var arr:number[]|string[]; 

即可以给arr = [1,2,4] ,也可以arr = [“Runoob”,“Google”,“Taobao”]

var arr:number[]|string[]; 
var i:number; 
arr = [1,2,4] 
console.log("**数字数组**")  for(i = 0;i<arr.length;i++) { console.log(arr[i]) 
}  arr = ["Runoob","Google","Taobao"] 
console.log("**字符串数组**")  for(i = 0;i<arr.length;i++) { console.log(arr[i]) 
}

接口(Interfaces)

可以理解为一种规范或者契约,它可以用来约定对象的结构,我们去使用一个接口就要去遵循这个接口的所有约定。在 typescript 中,接口最直观的体现是,约定一个对象当中具体应该有那些成员,并且这些成员是什么类型的。

基本用法

interface Post {// 多个成员可使用 ','、';' 分割,也可以不用title: stringcontent: string
}// 对于这个函数所接收的 post 对象,他就有一定的要求
// 所传入的对象必须要有一个 title 属性和 content 属性
// 只不过这种要求实际上是隐性的,它没有明确的表达出来
// 这种情况下我们就可以使用接口去表现出来这种约束
function printPost (post: Post) {console.log(post.title)console.log(post.content)
}printPost({title: 'Hello TypeScript',content: 'A javascript superset'
})

定义了一个接口 Post ,接着把post的数据{title:“”,content:“”},它的类型是 Post 。printPost实现了接口 IPerson 的属性和方法。

编译之后,我们没有发现任何有关接口的代码,其实 typescript 的接口只是为我们有结构的数据做类型约束,在运行阶段这种接口没有意义。
在这里插入图片描述

联合类型和接口
interface RunOptions { program:string; commandline:string[]|string|(()=>string); 
} // commandline 是字符串
var options:RunOptions = {program:"test1",commandline:"Hello"}; 
console.log(options.commandline)  // commandline 是字符串数组
options = {program:"test1",commandline:["Hello","World"]}; 
console.log(options.commandline[0]); 
console.log(options.commandline[1]);  // commandline 是一个函数表达式
options = {program:"test1",commandline:()=>{return "**Hello World**";}}; var fn:any = options.commandline; 
console.log(fn());
接口和数组

接口中我们可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串。

设置元素为字符串类型:

interface namelist { [index:number]:string 
} // 类型一致,正确
var list2:namelist = ["Google","Runoob","Taobao"]
// 错误元素 1 不是 string 类型
// var list2:namelist = ["Runoob",1,"Taobao"]
接口继承

接口继承就是说接口可以通过其他接口来扩展自己。

Typescript 允许接口继承多个接口。

继承使用关键字 extends

单接口继承语法格式:
Child_interface_name extends super_interface_name
多接口继承语法格式:
Child_interface_name extends super_interface1_name, super_interface2_name,,super_interfaceN_name

继承的各个接口使用逗号 , 分隔。

接口成员分类

可选成员

果说我们在一个对象当中,我们某个成员是可有可无的,那对于约束这个对象的接口来说,我们可以使用可选成员这样的一个特性。

interface Post {title: stringcontent: stringsubtitle?: string // 可选成员
}
只读成员

初始化过后不能再修改

interface Post {title: stringcontent: stringsubtitle?: string // 可选成员readonly summary: string // 只读成员
}
动态成员

一般用于一些有动态成员的对象,例如程序当中的缓存对象,它在运行当中会出现一些动态的键值。

interface Cache {// [属性名称(不是固定的,可以是任意名称), 键的类型]:值的类型[prop: string]: string
}// 创建一个 cache 对象实现这个 Cache 接口
const cache: Cache = {}// 动态添加任意的成员,这些成员都必须遵循 Cache 接口的类型约束
cache.foo = 'value1'
cache.bar = 'value2'

类 (Classes)

类的基本使用

TypeScript 类定义方式如下:

class class_name { // 类作用域
}

作用:描述一类具体事物的抽象特征。

定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):

  • 字段 − 字段是类里面声明的变量。字段表示对象的有关数据。
  • 构造函数 − 类实例化时调用,可以为类的对象分配内存。
  • 方法 − 方法为对象要执行的操作。
class Car { // 字段 engine:string; // 构造函数 constructor(engine:string) { this.engine = engine }  // 方法 disp():void { console.log("发动机为 :   "+this.engine) } 
}

例如:手机就是一个类型,这个类型的特征就是可以用来打电话和发短信,在这个类型下面还有一些细分的子类,而这些子类一定会满足父类的所有特征,而还会多出一些额外的特征。如智能手机,除了可以打电话和发短信,还可以使用一些
app,而我们是不能直接去使用类的,而是使用属于这个类的具体事物,例如我手上的智能手机。类比到程序的角度,类也是一样的,它是用来描述一类具体对象的抽象成员。ES6
以前,都是使用函数+原型 模拟实现类,ES6 开始 JavaScript中 有了专门的 class。而在 TypeScript
当中,除了可以使用 ECMA 标准当中所有类的功能,TypeScript 还增强了 class 的相关语法。

在 ES6 以前,都是通过 函数 + 原型 模拟实现类,从 ES6 开始 JavaScript 中有了专门的 class,在 TypeScript 中 增强了 class 的相关语法。

类的使用注意点:

直接使用 this 去访问当前类的属性会报错,是因为在 TypeScript 当中,我们要明确在类型当中去声明它所拥有的一些属性,而不是直接在构造函数当中通过 this 动态添加。

在 typescript 当中,类的属性必须要有一个初始值,要么在声明的时候通过=号去赋值,要么就在构造函数里初始化。

类的基本写法

class Person {// 声明这个类所拥有的一些属性name: stringage: numberconstructor (name: string, age: number) {// 类的属性必须要有一个初始值// 一般我们都是在构造函数里面去动态设置一个初始值this.name = namethis.age = age}sayHi (msg: string): void {console.log(`I am ${this.name}, ${msg}`)}
}
访问修饰符

类中的每一个成员我们都可以使用访问修饰符去修饰。

  • private:私有成员,只能在类的内部访问
  • public:公有成员(默认是public)
  • protected:受保护的成员(外部不能访问)但可以在子类中访问
构造函数的访问修饰符

默认也是 public,如果我们在构造函数前面加一个 private,那么这个类就不能在外部被实例化,也不能被继承,这样的一种情况下我们只能够在类的内部添加一个静态方法,然后在这个静态方法当中创建这个类的实例。

class Person {public name: stringprivate age: numberprotected gender: booleanconstructor (name: string, age: number) {this.name = namethis.age = agethis.gender = true}sayHi (msg: string): void {console.log(`I am ${this.name}, ${msg}`)}
}class Student extends Person {private constructor (name: string, age: number) {super(name, age)}static create (name: string, age: number) {return new Student(name, age)}
}const jack = Student.create('jack', 18)

如果将构造函数标记为 Protected,也是不能够在外部被实例化,但是相比于 private ,它是运行继承的。

只读属性

使用 readonly 关键词设置成员只读,初始化过后,readonly 不管在外部还是内部都不允许再修改。

class Person {public name: stringprivate age: numberprotected readonly gender: booleanconstructor (name: string, age: number) {this.name = namethis.age = agethis.gender = true}sayHi (msg: string): void {console.log(`I am ${this.name}, ${msg}`)}
}

类与接口

类与类之间的一些共同点可以用接口去抽象,比如 人 和 动物 都有相同的特点,吃和行走,我们就可以通过接口去约束这两个类的公共能力。

interface EatAndRUn {eat (food: string) : voidrun (distance: number) : void
}// 通过关键字 implements 实现 这个 EatAndRUn 接口
// 此时这个类必须要有这个接口对应的成员
class Person implements EatAndRUn{eat (food: string): void {console.log(`优雅的进餐:${food}`)}run (distance: number) {console.log(`直立行走:${distance}`)}
}class Animal implements EatAndRUn{eat (food: string): void {console.log(`呼噜呼噜的吃:${food}`)}run (distance: number) {console.log(`爬行:${distance}`)}
}

需要注意的是:在 C# 和 Java 这些语言当中,它建议我们尽可能让每个接口的定义更加简单更加细化,因此我们建议一个接口只去约束一个能力,让一个类同时实现多个接口。

interface Eat {eat (food: string): void
}interface Run {run (distance: number): void
}class Person implements Eat, Run {eat (food: string): void {console.log(`优雅的进餐: ${food}`)}run (distance: number) {console.log(`直立行走: ${distance}`)}
}class Animal implements Eat, Run {eat (food: string): void {console.log(`呼噜呼噜的吃: ${food}`)}run (distance: number) {console.log(`爬行: ${distance}`)}
}

抽象类

抽象类在某种程度上跟接口有点类似,它也是用来约束子类当中必须要拥有某些成员,但是不同于接口的是,抽象类可以包含一些具体的实现,而接口只能够是一些成员的抽象,不包含具体的实现,一些比较大的类目建议使用抽象类,比如动物类,因为我们所说的动物它只是一个泛指,并不够具体,那在它的下面一定有更细化的分类,例如小狗小猫之类。

定义抽象类的方式:通过关键词 abstract

类型被定义为抽象类过后,它只能够被继承,不能够再使用 new 的方式去创建对应的实例对象,在这种情况下我们就必须要使用 子类 去继承这个类型。
在抽象类当中我们还可以去定义一些抽象方法,需要注意的是抽象方法也不需要方法体。
当我们的父类有抽象方法时,我们的子类就必须要实现这个方法。

abstract class Animal {eat (food: string): void {console.log(`呼噜呼噜的吃: ${food}`)}abstract run (distance: number): void
}class Dog extends Animal {run(distance: number): void {console.log('四脚爬行', distance)}}const d = new Dog()
d.eat('嗯西马')
d.run(100)

可以使用 vscoe 的代码修正功能,自动去生成所对应的方法现实:
在这里插入图片描述

泛型(Generics)

指的是我们去定义函数,接口,类的时候没有去定义具体类型,我们在使用的时候再去定义指定类型的这一种特征。

以函数为例,泛型 就是我们在声明一个函数的时候不去指定一个类型,等我们调用的时候再传入一个具体的类型,这样做的目的是极大程度的复用我们的代码。

比如 定义一个创建 number 类型和 string 类型数组的方法:

不使用泛型:
// 定义一个创建 number 类型的方法
function createNumberArray (length: number, value: number): number[] {const arr = Array<number>(length).fill(value)return arr
}
// 定义一个创建 string 类型的方法
function createStringArray (length: number, value: string): string[] {const arr = Array<string>(length).fill(value)return arr
}const numArr = createNumberArray(3, 100)
const strArr = createNumberArray(3, 'foo')
使用泛型:

把类型用一个泛型参数 T 表示,把函数当中不明确类型用 T 去代表,在使用的时候再传递具体类型。如下:

function createArray<T> (length: number, value: T): T[] {const arr = Array<T>(length).fill(value)return arr
}const numArr = createArray<number>(3, 100)
const strArr = createNumberArray<string>(3, 'foo')

其实 Array 是一个泛型类,在 typescript 中去定义这个 Array 类型时,它不知道我们使用它去存放什么样类型的数据,所以它就使用泛型参数,在我们去调用的时候再传入具体类型,这是一个泛型提现。
在这里插入图片描述

总的来说,泛型就是在我们定义的时候把不明确的类型,变成一个参数,在我们使用的时候再传递这样的一个类型参数。

类型声明

在实际开发过程中,难免会使用一些第三方 npm 模块,而这些第三方模块不一定是通过 typescript 编写的,所以它提供的成员就不会有强类型的体验。

比如我们常见的 lodash:
在这里插入图片描述

解决方式

  • 单独的类型声明,使用 declare 语句声明一下函数的类型;
import { camelCase } from 'lodash'declare function camelCase(input: string): stringconst res = camelCase('hello typed')

这就是所谓的类型声明,说白了就是一个成员在定义的时候由于某种原因,还没声明一个明确的类型,我们在使用的时候可以单独为它再做一次声明,这种用法存在的原因,为的是考虑兼容一些普通模块的js。

  • 安装其所对应的类型声明模块

由于 typescript 的社区很强大,绝大部分的常用的 npm 模块都已经做了对应的类型声明,我们只需要安装其所对应的类型声明模块就行了。

其实我们可以在导入时候的错误信息看到对应的提示:
在这里插入图片描述

比如 lodash 安装其所对应的类型声明模块

add @types/lodash --dev

安装完毕之后我们就可以看到相应的类型提示了:
在这里插入图片描述
现在越来越多模块已经在内部集成了这些类型声明的文件,很多时候我们都不需要单独安装类型声明模块了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/636113.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从数据角度分析年龄与NBA球员赛场表现的关系【数据分析项目分享】

好久不见朋友们&#xff0c;今天给大家分享一个我自己很感兴趣的话题分析——NBA球员表现跟年龄关系到底大不大&#xff1f;数据来源于Kaggle&#xff0c;感兴趣的朋友可以点赞评论留言&#xff0c;我会将数据同代码一起发送给你。 目录 NBA球员表现的探索性数据分析导入Python…

【 Qt 快速上手】-①- Qt 背景介绍与发展前景

文章目录 1.1 什么是 Qt1.2 Qt 的发展史1.3 Qt 支持的平台1.4 Qt 版本1.5 Qt 的优点1.6 Qt的应用场景1.7 Qt的成功案例1.8 Qt的发展前景及就业分析行业发展方向就业方面的发展前景 1.1 什么是 Qt Qt 是一个跨平台的 C 图形用户界面应用程序框架。它为应用程序开发者提供了建立…

DBA技术栈MongoDB:简介

1.1 什么是MongoDB&#xff1f; MongoDB是一个可扩展、开源、表结构自由、用C语言编写且面向文档的数据库&#xff0c;旨在为Web应用程序提供高性能、高可用性且易扩展的数据存储解决方案。 MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当…

linux下USB抓包和分析流程

linux下USB抓包和分析流程 在windows下抓取usb包时可以通过wireshark安装时安装USBpcap来实现usb抓包&#xff0c;linux下如何操作呢&#xff1f; 是基于usbmon&#xff0c;本博客简单描述基于usbmon在linux系统上对通过usb口进行发送和接收的数据的抓包流程&#xff0c;分别描…

SCI期刊查询利器:影响因子和分区情况一站式查询

参考 本文仅作为学术分享,如果侵权,会删文处理 期刊的影响因子,最传统也最靠谱的方法就是去 Journal Citation Reports 官方平台上面查询,JCR 平台直接输入期刊名称检索,或者按照类别查找期刊:如果在校外没有访问JCR的权限,可以购买80图书馆的WOS套餐,仅需38元,不到一…

【51单片机系列】proteus仿真单片机的串口通信

本文参考&#xff1a;https://zhuanlan.zhihu.com/p/425809292。 在proteus之外使用串口软件和单片机通信。通过在proteus设计一个单片机接收PC发送的数据&#xff0c;并将接收的数据发送出去&#xff0c;利用软件【Configure Virtual Serial Port Driver】创建一对虚拟串口&am…

Linux指令权限知识点总结

目录 周边知识 基础指令思维导图 权限思维导图 周边知识 大多数后端操作系统都是Linux操作系统操作系统是管理软件和硬件的软件Linux是一款操作系统Linux分为技术版本和商业版本Linux的文件是以多叉树的形式构建隐藏文件 . 和 ...可以表示当前路径。可以形成可执行文件&a…

关于ElasticSearch,你应该知道的

一、集群规划优化实践 1、基于目标数据量规划集群 在业务初期&#xff0c;经常被问到的问题&#xff0c;要几个节点的集群&#xff0c;内存、CPU要多大&#xff0c;要不要SSD&#xff1f; 最主要的考虑点是&#xff1a;你的目标存储数据量是多大&#xff1f;可以针对目标数据…

用LED数码显示器循环显示数字0~9

#include<reg51.h> // 包含51单片机寄存器定义的头文件 /************************************************** 函数功能&#xff1a;延时函数&#xff0c;延时一段时间 ***************************************************/ void delay(void) { unsigned …

phpmyadmin 创建服务器

phpmyadmin默认的服务器是localhost 访问setup&#xff0c;创建新的服务器 添加服务器信息 点击应用&#xff0c;服务器创建成功 下载配置文件config.inc.php&#xff0c;放到WWW目录下 可再次访问setup&#xff0c;发现已配置过了 访问登录页面&#xff0c;发现可选…

第十一章 请求响应

第十一章 请求响应 1.概述2.请求-postman工具3.请求-简单参数&实体参数4.请求-数组集合参数5.请求-日期参数&JSON参数6.请求-路径参数7.响应-ResponseBody&统一响应结果8.响应-案例 1.概述 将前端发送的请求封装为HttpServletRequest对象 在通过HttpServletRespo…

OpenCV-Python(51):基于Haar特征分类器的面部检测

目标 学习了解Haar 特征分类器为基础的面部检测技术将面部检测扩展到眼部检测等。 基础 以Haar 特征分类器为基础的对象检测技术是一种非常有效的对象检测技术(2001 年Paul_Viola 和Michael_Jones 提出)。它是基于机器学习的,通过使用大量的正负样本图像训练得到一个cascade_…

【Linux取经路】初探进程地址空间

文章目录 一、历史问题回顾二、语言层面的地址空间2.1 验证 三、虚拟地址的引入3.1 初步解释这种现象——引入地址空间的概念3.2 再来粗粒度理解上面的现象 四、细节解释4.1 地址空间究竟是什么&#xff1f;4.2为什么要有地址空间4.3 页表4.3.1 CR3寄存器4.3.2 页表是由页表项组…

【Linux的基本指令】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 1、ls 指令 2、 pwd命令 3、cd 指令 4、touch指令 5、mkdir指令&#xff08;重要&#xff09; 6、rmdir指令 && rm 指令&#xff08;重要&#xff09;…

前后端分离,仓储模式的医院安全(不良)事件报告系统

医院安全&#xff08;不良&#xff09;事件报告系统源码&#xff0c;PHP语言开发 医院不良事件上报系统&#xff0c;按照不良事件的管理部门不同&#xff0c;分为护理不良事件、药品不良反应事件、医技不良事件、院内感染事件、输血不良反应事件、器械不良事件、信息不良事件、…

国产AI新篇章:书生·浦语2.0带来200K超长上下文解决方案

总览&#xff1a;大模型技术的快速演进 自2023年7月6日“书生浦语”&#xff08;InternLM&#xff09;在世界人工智能大会上正式开源以来&#xff0c;其在社区和业界的影响力日益扩大。在过去半年中&#xff0c;大模型技术体系经历了快速的演进&#xff0c;特别是100K级别的长…

力扣:474. 一和零(动态规划)(01背包)

题目&#xff1a; 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#xff0c;集合 x 是集合 y 的 子集 。 示例 1&#xff1a; 输入&#…

JOSEF约瑟 零序过流继电器LGL-110/AC AC220V 0.01~9.99A 柜内安装

LGY 、LGL零序过电压继电器 系列型号 LGY-110零序过电压继电器&#xff1b; LGL-110零序过电压继电器&#xff1b; LGL-110/AC零序过电压继电器&#xff1b; LGL-110静态零序过电流继电器 &#xff11; 应用 LGL-110 型零序过电流继电器用作线路和电力设备的零序过电流保护。…

一文详解Bitcoin Wallet(btc钱包),推荐bitget钱包

​ 比特币&#xff08;BTC&#xff09;是什么&#xff1f; 比特币&#xff08;BTC&#xff09;于 2008 年由中本聪创建&#xff0c;是一个去中心化的点对点网络。这个开创性的系统运用了密码学技术和分布式账本技术&#xff0c;无需中央权威机构的验证。比特币的诞生标志着去中…

【工具】使用ssh进行socket5代理

文章目录 shellssh命令详解正向代理&#xff1a;反向代理&#xff1a;本地 socks5 代理 shell ssh -D 3333 root192.168.0.11 #输入密码 #3333端口已经使用远程机进行转发设置Windows全局代理转发 socks127.0.0.1 3333如果远程机为公网ip&#xff0c;可通过搜索引擎查询出网…