TypeScript快速上手
TypeScript快速上手
参考TypeScript零基础入门 轻松搞定ts进行整理
TS文档:TypeScript: The starting point for learning TypeScript (typescriptlang.org)
什么是TypeScript?
TypeScript 是一种由微软开发的自由和开源的编程语言,它是 JavaScript 的一个超集,扩展了JavaScript 的语法。
TypeScript 是面向对象的 JavaScript。(类)
简单对理解,TypeScript
就是带有类型检测
的 JavaScript
。
JavaScript 与 TypeScript 的区别
TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法。
因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。
TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
TypeScript 开发环境
NPM 安装 TypeScript
npm install -g typescript
安装完成后我们可以使用 tsc
命令来执行 TypeScript 的相关代码,以下是查看版本号:
$ tsc -v
Version 5.1.6
新建一个 app.ts 的文件
var message:string = "Hello World"
console.log(message)
通常我们使用 .ts 作为 TypeScript 代码文件的扩展名。
然后执行以下命令将 TypeScript 转换为 JavaScript 代码:
tsc app.ts
这时候在当前目录下(与 app.ts 同一目录)就会生成一个 app.js 文件,代码如下:
var message = "Hello World";
console.log(message);
使用 node 命令来执行 app.js 文件:
$ node app.js
Hello World
运行ts命令
执行命令
tsc -init
运行命令监测(这个时候写的TS会自动更新)
tsc -w
再开启一个终端:
node xxx.js
类型声明
类型声明是TS非常重要的一个特点
通过类型声明可以指定TS中变量(参数、形参)的类型
指定类型后,当变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,反之报错
类型声明就是给变量设置了类型,使得变量只能存储某种类型的值
语法如下
let 变量名 : 类型
let 变量名 : 类型 = 值
function fn(参数: 类型,参数: 类型):类型{
...
}
自动类型判断
TS拥有自动的类型判断机制
当对变量的声明和赋值同时进行时,TS编译器会自动判断变量类型
当变量声明和赋值同时进行时,可以省略掉类型声明
TypeScript基础类型
类型 | 例子 | 描述 |
---|---|---|
number | 2.66,-6 | 任意数字 |
string | "du","student" | 任意字符串 |
boolean | true/false | 布尔值true/false |
字面量 | 字面量的本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any类型 |
void | 空值(undefined) | 没有值或undefined |
never | 没有值 | 不能是任何值 |
object | 任意的JS对象 | |
arrray | [6,66,666] | 任意的JS数组 |
tuple | [66,666] | 元组,TS的新增类型,是一种固定长度的数组 |
enum | enum(A.B) | 枚举类型,TS中新增类型 |
1.字符串类型
字符串是使用string定义的
//普通声明
let aa: string = 'hello'
//也可以使用es6的字符串模板
let str: string = `啊哈哈哈${aa}`
2.数字类型
支持十六进制、十进制、八进制和二进制;
let notANumber: number = NaN;//Nan
let num: number = 123;//普通数字
let infinityNumber: number = Infinity;//无穷大
let decimal: number = 6;//十进制
let hex: number = 0xf00d;//十六进制
let binary: number = 0b1010;//二进制
let octal: number = 0o744;//八进制s
3.布尔类型
注意,使用构造函数 Boolean 创造的对象不是布尔值:
//这样会报错 应为事实上 new Boolean() 返回的是一个 Boolean 对象
let createdBoolean: boolean = new Boolean(1)
//事实上 new Boolean() 返回的是一个 Boolean 对象 需要改成
let createdBoolean: Boolean = new Boolean(1)
let booleand: boolean = true //可以直接使用布尔值
let booleand2: boolean = Boolean(1) //也可以通过函数返回布尔值
4.空值类型
JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数
function voidFn(): void {
console.log('test void')
}
void 类型的用法,主要是用在我们不希望调用者关心函数返回值的情况下,比如通常的异步回调函数声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:
let u: void = undefined
let n: void = null;//会报错--需要关闭严格模式
5.Null和undefined类型
let u: undefined = undefined;//定义undefined
let n: null = null;//定义null
void 和 undefined 和 null 最大的区别
//这样写会报错 void类型不可以分给其他类型
let test: void = undefined
let num2: string = "1"
num2 = test
//这样是没问题的
let test: null = null
let num2: string = "1"
num2 = test
//或者这样的
let test: undefined = undefined
let num2: string = "1"
num2 = test
注意:
如果你配置了tsconfig.json 开启了严格模式
{
"compilerOptions":{
"strict": true
}
}
null 不能 赋予 void 类型
6.Any 类型 和 unknown 顶级类型
any类型
1.没有强制限定哪种类型,随时切换类型都可以 我们可以对 any 进行任何操作,不需要检查类型
let anys:any = 123
anys = '123'
anys = true
- 声明变量的时候没有指定任意类型默认为any
let anys;
anys = '123'
anys = true
- 弊端:如果使用any 就失去了TS类型检测的作用4.TypeScript 3.0中引入的 unknown 类型也被认为是 top type ,但它更安全。与 any 一样,所有
类型都可以分配给unknown
unknow类型
unknow类型比any更加严格当你要使用any 的时候可以尝试使用unknow
//unknown 可以定义任何类型的值
let value: unknown;
value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = null; // OK
value = undefined; // OK
value = Symbol("type"); // OK
any与unknow区别
区别1:
//这样写会报错unknow类型不能作为子类型只能作为父类型 any可以作为父类型和子类型
//unknown类型不能赋值给其他类型
let names:unknown = '123'
let names2:string = names
//这样就没问题 any类型是可以的
let names:any = '123'
let names2:string = names
//unknown可赋值对象只有unknown 和 any
let bbb:unknown = '123'
let aaa:any= '456'
aaa = bbb
区别2
//如果是any类型在对象没有这个属性的时候还在获取是不会报错的
let obj:any = {b:1}
obj.a
//如果是unknow 是不能调用属性和方法
let obj:unknown = {b:1,ccc:():number=>213}
obj.b
obj.ccc()
7.数组类型
a. 数组变量名: 原始类型[]
b. 数据变量名:Array<原始类型>
1.类型[]
//类型加中括号 数组的项中不允许出现其他的类型:
let arr:number[] = [123]
//这样会报错定义了数字类型出现字符串是不允许的
let arr:number[] = [1,2,3,'1']
//操作方法添加也是不允许的
let arr:number[] = [1,2,3,]
arr.unshift('1')
var arr: number[] = [1, 2, 3]; //数字类型的数组
var arr2: string[] = ["1", "2"]; //字符串类型的数组
var arr3: any[] = [1, "2", true]; //任意类型的数组
2.数组泛型
规则: Array<类型>
let arr: Array<number> = [1,2,3,4,5]
3.any 在数组中的应用
一个常见的例子数组中可以存在任意类型
let list: any[] = ['test', 1, [],{a:1}]
8.联合类型
通过联合类型将多个类型组合成一个类型
内容:
需求:数组中既有 number 类型,又有 string 类型,这个数组的类型应该如何写?
// 此处 () 的目的是为了将提升优先级,表示:number 类型的数组或 string 类型的数组
let arr: (number | string)[] = [1, 'a', 3, 'b']
解释:
|(竖线)在 TS 中叫做"联合类型"
,即:由两个或多个其他类型组成的类型,表示可以是这些类型中的任意一种注意:这是 TS 中联合类型的语法,只有一根竖线,不要与 JS 中的或(|| 或)混淆了
9.类型别名
使用类型别名给类型起别名 实现复用类型
语法:type 类型名 = 类型
内容:
- 类型别名(自定义类型):为任意类型起别名
- 使用场景:当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型的使用
type CustomArray = (number | string)[]
let arr1: CustomArray = [1, 'a', 3, 'b']
let arr2: CustomArray = ['x', 'y', 6, 7]
解释:
a. 使用 type 关键字来创建自定义类型
b. 类型别名(比如,此处的 CustomArray)可以是任意合法的变量名称
c. 推荐使用大写字母开头
d. 创建类型别名后,直接使用该类型别名作为变量的类型注解即可
10.函数类型-参数和返回值
函数指定类型
内容:
函数的类型实际上指的是:
函数参数和返回值的类型
为函数指定类型的两种方式:
a. 单独指定参数、返回值的类型
b. 同时指定参数、返回值的类型
a. 单独指定参数、返回值的类型:
// 函数声明
function add(num1: number, num2: number): number {
return num1 + num2
}
// 箭头函数
const add = (num1: number, num2: number): number => {
return num1 + num2
}
b. 同时指定参数、返回值的类型:
- 解释:当函数作为表达式时,可以通过类似箭头函数形式的语法来为函数添加类型
- 注意:这种形式
只适用于函数表达式
// 创建函数自定义类型
type AddFn = (num1: number, num2: number) => number
// 使用自定义类型作为函数 add 的类型
const add: AddFn = (num1, num2) => {
return num1 + num2
}
函数类型-void 类型
- 如果函数没有返回值,那么,函数返回值类型为:void
function greet(name: string): void {
console.log('Hello', name)
}
- 注意:如果一个函数没有返回值,此时,在 TS 的类型中,应该使用 void 类型
- 注意:不要与 undefined 类型混淆
// 如果什么都不写,此时,add 函数的返回值类型为: void
const add = () => {}
// 但,如果指定 返回值类型为 undefined,此时,函数体中必须显示的 return undefined 才可以
const add = (): undefined => {
// 此处,返回的 undefined 是 JS 中的一个值
return undefined
}
函数类型-可选参数
- 使用函数实现某个功能时,参数可以传也可以不传。这种情况下,在给函数参数指定类型时,就用到可选参数了
- 比如,数组的 slice 方法,可以 slice() 也可以 slice(1) 还可以 slice(1, 3)
function mySlice(start?: number, end?: number): void {
console.log('起始索引:', start, '结束索引:', end)
}
- 可选参数:在可传可不传的参数名称后面添加 ?(问号)
- 注意:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数
- 注意:参数默认值和可选参数互斥的,一般只需要指定一种即可
- 注意:如果参数有默认值,那么该参数默认就是可选的
11.对象类型
- JS 中的对象是由属性和方法构成的,而 TS 对象的类型就是在描述对象的结构(有什么类型的属性和方法)
- 对象类型的写法:变量名:{属性名1:Type1,属性名2:Type2,...}
// 空对象
let person: {} = {}
// 有属性的对象
let person: { name: string } = {
name: '程序员'
}
// 既有属性又有方法的对象
// 在一行代码中指定对象的多个属性类型时,使用 `;`(分号)来分隔
let person: { name: string; sayHi(name: string): void } = {
name: 'jack',
sayHi(name) {}
}
// 对象中如果有多个类型,可以换行写:
// 通过换行来分隔多个属性类型,可以去掉 `;`
let person: {
name: string
sayHi(): void
} = {
name: 'jack',
sayHi() {}
}
解释:
a. 使用 {} 来描述对象结构
b. 属性采用属性名: 类型的形式
c. 方法采用方法名(参数: 参数的类型): 返回值类型的形式
对象类型-使用类型别名-type
- 注意:直接使用 {} 形式为对象添加类型,会降低代码的可读性(不好辨识类型和值)
- 推荐:使用类型别名为对象添加类型
// 创建类型别名
type Person = {
name: string
sayHi(): void
}
// 使用类型别名作为对象的类型:
let person: Person = {
name: 'jack',
sayHi() {}
}
对象类型-带有参数的方法类型
- 如果方法有参数,就在方法名后面的小括号中指定参数类型
type Person = {
greet(name: string): void
}
let person: Person = {
greet(name) {
console.log(name)
}
}
- 方法的类型也可以使用箭头函数形式
type Person = {
greet: (name: string) => void
}
let person: Person = {
greet(name) {
console.log(name)
}
}
对象类型-对象可选属性
- 对象的属性或方法,也可以是可选的,此时就用到可选属性了
- 比如,我们在使用 axios({ ... }) 时,如果发送 GET 请求,method 属性就可以省略
- 可选属性的语法与函数可选参数的语法一致,都使用 ? 来表示
type Config = {
url: string
method?: string
}
function myAxios(config: Config) {
console.log(config)
}
任意属性 [propName: string]
需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
//在这个例子当中我们看到接口中并没有定义C但是并没有报错
//应为我们定义了[propName: string]: any;
//允许添加新的任意属性
interface Person {
b?:string,
a:string,
[propName: string]: any;
}
const person:Person = {
a:"213",
c:"123"
}
只读属性 readonly
readonly 只读属性是不允许被赋值的只能读取
//这样写是会报错的
//应为a是只读的不允许重新赋值
interface Person {
b?: string,
readonly a: string,
[propName: string]: any;
}
const person: Person = {
a: "213",
c: "123"
}
person.a = 123
添加函数
interface Person {
b?: string,
readonly a: string,
[propName: string]: any;
cb:()=>void
}
const person: Person = {
a: "213",
c: "123",
cb:()=>{
console.log(123)
}
}
对象类型-接口
-interface
内容:
当一个对象类型被多次使用时,也可以使用接口(interface)来描述对象的类型,达到复用的目的
解释:
- 使用 interface 关键字来声明接口
- 接口名称(比如,此处的 IPerson),可以是任意合法的变量名称,推荐以 I 开头
- 声明接口后,直接使用接口名称作为变量的类型
- 因为每一行只有一个属性类型,因此,属性类型后没有 ;(分号)
interface IPerson {
name: string
age: number
sayHi(): void
}
let person: IPerson = {
name: 'jack',
age: 19,
sayHi() {}
}
//重名interface 可以合并
interface A{name:string}
interface A{age:number}
var x:A={name:'xx',age:20}
//继承
interface A{
name:string
}
interface B extends A{
age:number
}
let obj:B = {
age:18,
name:"string"
}
对象类型-interface vs type
内容:interface(接口)和 type(类型别名)的对比:
相同点:都可以给对象指定类型
不同点:
接口,只能为对象指定类型
类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名
注意:interface 和 type 在使用上还有其他的不同之处,请参考文档说明TypeScript: Documentation - Everyday Types (typescriptlang.org)
约定:能使用 type 就是用 type
interface IPerson {
name: string
age: number
sayHi(): void
}
// 为对象类型创建类型别名
type IPerson = {
name: string
age: number
sayHi(): void
}
// 为联合类型创建类型别名
type NumStr = number | string
对象类型-接口继承
内容:
如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用
比如,这两个接口都有 x、y 两个属性,重复写两次,可以,但很繁琐
interface Point2D { x: number; y: number }
interface Point3D { x: number; y: number; z: number }
使用接口继承,来简化:
- 使用
extends(继承)
关键字实现了接口 Point3D 继承 Point2D - 继承后,Point3D 就有了 Point2D 的所有属性和方法(此时,Point3D 同时有 x、y、z 三个属性)
interface Point2D { x: number; y: number }
// 继承 Point2D
interface Point3D extends Point2D { z: number }
// 继承后 Point3D 的结构:{ x: number; y: number; z: number }
交叉类型
能够使用交叉类型模拟接口继承的功能
内容:
- 语法:
& 交叉类型
(intersection types) - 作用:组合现有的对象类型
- 比如,Point3D 组合了 Point2D 和 后面的对象,所以,Point3D 就同时具有了 Point2D 和 后面对象中的所有属性
// 使用 type 自定义类型来模拟 Point2D 和 Point3D
type Point2D = {
x: number
y: number
}
// 使用 交叉类型 来实现接口继承的功能:
// 使用 交叉类型 后,Point3D => { x: number; y: number; z: number }
// 也就是同时具有了 Point2D 和 后面对象 的所有的属性了
type Point3D = Point2D & {
z: number
}
let o: Point3D = {
x: 1,
y: 2,
z: 3
}
12.元组类型
元组类型是ts新增的类型之一,元组最重要的特性是可以限制数组元素的个数和类型,它特别适合用来实现多值返回。
可以说元组就是固定长度的数组,下面开始介绍元组的语法
可以使用数组来记录坐标,那么,该数组中只有两个元素,并且这两个元素都是数值类型
使用 number[] 的缺点:不严谨,因为该类型的数组中可以出现任意多个数字
let position: number[] = [116.2317, 39.5427]
更好的方式:元组 Tuple
- 元组类型是另一种类型的数组,它确切地知道包含多少个元素,以及特定索引对应的类型
- 元组类型可以确切地标记出有多少个元素,以及每个元素的类型
// 该示例中,元素有两个元素,每个元素的类型都是 number
let x: [string, number]; // 类型必须匹配且个数必须为2
x = ['hello', 10]; // OK
x = ['hello', 10,10]; // Error
x = [10, 'hello']; // Error
元组类型 可选参数
let a : [string,number?];
a=['12'] //通过
a=['asd',1] //通过
a=[1,1] //不通过,第一个元素应该为字符串类型
实际上,React 中 useState
hook 的返回值类型就是一个元组类型
// 因为对于 useState 来说,它的返回值长度固定切每个索引对应的元素类型也是知道的
const [loading, setLoading] = useState(false)
13.Enum 枚举类型
使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript 支持数字的和基于字符串的枚举。
参考原文:https://youjia.sx.cn/you-dont-know-ts/docs/theme-reco/base-2.html#_2-5-array-类型
数字枚举
enum Direction {
NORTH,
SOUTH,
EAST,
WEST,
}
let dir: Direction = Direction.NORTH;
默认情况下,NORTH
的初始值为 0,其余的成员会从 1 开始自动增长。换句话说,Direction.SOUTH
的值为 1,Direction.EAST
的值为 2,Direction.WEST
的值为 3。
当然我们也可以设置 NORTH 的初始值,比如:
enum Direction {
NORTH = 3,
SOUTH,
EAST,
WEST,
}
字符串枚举
在 TypeScript 2.4 版本,允许我们使用字符串枚举。在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。
enum Direction {
NORTH = "NORTH",
SOUTH = "SOUTH",
EAST = "EAST",
WEST = "WEST",
}
通过观察数字枚举和字符串枚举的编译结果,我们可以知道数字枚举除了支持 从成员名称到成员值 的普通映射之外,它还支持 从成员值到成员名称 的反向映射:
enum Direction {
NORTH,
SOUTH,
EAST,
WEST,
}
let dirName = Direction[0]; // NORTH
let dirVal = Direction["NORTH"]; // 0
另外,对于纯字符串枚举,我们不能省略任何初始化程序。而数字枚举如果没有显式设置值时,则会使用默认规则进行初始化。
常量枚举
除了数字枚举和字符串枚举之外,还有一种特殊的枚举 —— 常量枚举。它是使用 const 关键字修饰的枚举,常量枚举会使用内联语法,不会为枚举类型编译生成任何 JavaScript。为了更好地理解这句话,我们来看一个具体的例子:
const enum Direction {
NORTH,
SOUTH,
EAST,
WEST,
}
let dir: Direction = Direction.NORTH;
异构枚举
异构枚举的成员值是数字和字符串的混合:
enum Enum {
A,
B,
C = "C",
D = "D",
E = 8,
F,
}
数字枚举相对字符串枚举多了 “反向映射”:
console.log(Enum.A); //输出:0
console.log(Enum[0]); // 输出:A
14.Never 类型
never 类型表示的是那些永不存在的值的类型。 例如,never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。
参考原文:https://youjia.sx.cn/you-dont-know-ts/docs/theme-reco/base-2.html#_2-12-object-object-和-类型
// 返回 never 的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
在 TypeScript 中,可以利用 never
类型的特性来实现全面性检查,具体示例如下:
type Foo = string | number;
function controlFlowAnalysisWithNever(foo: Foo) {
if (typeof foo === "string") {
// 这里 foo 被收窄为 string 类型
} else if (typeof foo === "number") {
// 这里 foo 被收窄为 number 类型
} else {
// foo 在这里是 never
const check: never = foo;
}
}
注意在 else
分支里面,我们把收窄为 never
的 foo
赋值给一个显示声明的 never
变量。如果一切逻辑正确,那么这里应该能够编译通过。但是假如后来有一天你的同事修改了 Foo
的类型:
type Foo = string | number | boolean;
然而他忘记同时修改 controlFlowAnalysisWithNever
方法中的控制流程,这时候 else
分支的 foo
类型会被收窄为 boolean
类型,导致无法赋值给 never
类型,这时就会产生一个编译错误。通过这个方式,我们可以确保controlFlowAnalysisWithNever
方法总是穷尽了 Foo
的所有可能类型。 通过这个示例,我们可以得出一个结论:使用 never
避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。
类型推论
内容:
在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型
换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写
发生类型推论的 2 种常见场景:
a. 声明变量并初始化时
b. 根据参数类型决定函数返回值时
// 变量 age 的类型被自动推断为:number
let age = 18
// 函数返回值的类型被自动推断为:number
// 注意:函数参数一定要添加类型
function add(num1: number, num2: number) {
return num1 + num2
}
- 推荐:能省略类型注解的地方就省略(偷懒,充分利用TS类型推论的能力,提升开发效率)
- 技巧:如果不知道类型,可以通过鼠标放在变量名称上,利用 VSCode 的提示来查看类型
- 推荐:在 VSCode 中写代码的时候,多看方法、属性的类型,养成写代码看类型的习惯(充分发挥 VSCode 的能力)
类型断言
使用TS中的类型断言指定更加具体的类型
内容:
有时候你会比 TS 更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型。 比如:
// 假设页面中有个 id 为 link 的 a 标签:
// <a id="link" href="http://itcast.cn/"></a>
// 我们希望通过 DOM 拿到 a 标签的 href 属性
const aLink = document.getElementById('a')
- 该方法返回值的类型是 HTMLElement,该类型只包含所有标签公共的属性或方法,不包含 a 标签特有的 href等属性
- 因此,这个类型太宽泛(不具体),无法操作
href
等a
标签特有的属性或方法 - 解决方式:这种情况下就需要使用类型断言指定更加具体的类型
使用类型断言:
- 使用
as
关键字实现类型断言 - 关键字
as
后面的类型是一个更加具体的类型(HTMLAnchorElement 是 HTMLElement 的子类型) - 通过类型断言,
aLink
的类型变得更加具体,这样就可以访问a
标签特有的属性或方法了
// 使用类型断言来指定为更加具体的 HTMLAnchorElement 类型
const aLink = document.getElementById('link') as HTMLAnchorElement
- 另一种语法,使用 <> 语法,这种语法形式不常用知道即可:
// 该语法,知道即可:
const aLink = <HTMLAnchorElement>document.getElementById('link')
技巧:在浏览器控制台,通过 __proto__
可以获取 DOM 元素的类型
any类型
内容:
原则:不推荐使用 any!这会让 TypeScript 变为 “AnyScript”(失去 TS 类型保护的优势)
- 解释:因为当值的类型为
any
时,可以对该值进行任意操作,并且不会有代码提示
let obj: any = { x: 0 }
obj.bar = 100
说明:尽可能的避免使用 any
类型,除非临时使用 any
来“避免”书写很长、很复杂的类型
其他隐式具有 any
类型的情况:
- 声明变量不提供类型也不提供默认值
- 函数参数不加类型
注意:因为不推荐使用 any
,所以,这两种情况下都应该提供类型
泛型
作用:泛型(Generics)可以在保证类型安全前提下,给别名、接口、函数等添加
类型参数
,从而实现复用
软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。
组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
在TypeScript中,泛型是一种创建可复用代码组件的工具。这种组件不只能被一种类型使用,而是能被多种类型复用。
类似于参数的作用,泛型是一种用以增强类型(types)、接口(interfaces)、函数类型等能力的非常可靠的手段。
泛型别名
语法:type 类型别名<Type1, Type2...> = {}
// 对后台返回的数据进行类型定义
type User = {
name: string;
age: number;
}
type Goods = {
id: number;
goodsName: string;
}
type Data<T> = {
msg: string;
code: number;
data: T
}
let obj:Data<number[]> = {
msg:'',
code:12,
data:[1,2]
}
// 使用类型
type UserData = Data<User>
type GoodsData = Data<Goods>
小结:
- 泛型:定义类型别名后加上<类型参数> 就是泛型语法, 使用的时候传入具体的类型即可
- 是一个变量,可以随意命名,建议遵循大驼峰即可。
- 和类型别名配合,在类型别名后加上泛型语法,然后类型别名内就可以使用这个类型参数
- 泛型可以提高类型的复用性和灵活性
泛型接口
掌握:泛型接口基本使用,实现类型复用,了解内置泛型接口interface 接口名<Type1,Type2...> {}
// 对象,获取单个ID函数,获取所有ID函数,ID的类型肯定是一致的,但是可能是数字可能是字符串
interface IdFn<T> {
id: () => T;
ids: () => T[];
}
const idObj: IdFn<number> = {
id() { return 1 },
ids() { return [1, 2] },
};
- 在接口名称的后面添加 <类型变量>,那么,这个接口就变成了泛型接口,接口中所有成员都可以使用类型变量。
内置的泛型接口:
const arr = [1, 2, 3];
// TS有自动类型推断,其实可以看做:const arr:Array<number> = [1, 2, 3]
arr.push(4);
arr.forEach((item) => console.log(item));
- 可以通过 Ctrl + 鼠标左键(Mac:Command + 鼠标左键) 去查看内置的泛型接口
泛型函数
掌握:泛型函数基本使用,保证函数内类型复用,且保证类型安全语法:const fn = <Type1,Type2...>(a:Type1, b:Type2):Type1=>{}
//语法:const fn=<Type1,Type2>(a:Type1,b:Type2):Type1=>{}
const fn1 = <First,Second>(a:First,b:Second)=>{}
//完整写法
fn1<number,number>(1,1)
fn1<string,boolean>('',true)
//TS有类型推断机制 可以省略不写
fn1(1,true)
// 函数的参数是什么类型,返回值就是什么类型
function getId<T>(id: T): T {
return id
}
let id1 = getId<number>(1)
// TS会进行类型推断,参数的类型作为泛型的类型 getId<string>('2')
let id2 = getId('2')
小结
泛型函数语法?
- 函数名称后加上
<T>
, T是类型参数,是个类型变量,命名建议遵循大驼峰即可。
- 函数名称后加上
T
什么时候确定?- 当你调用函数的时候,传入具体的类型,T 或捕获到这个类型,函数任何位置均可使用。
泛型函数好处?
- 让函数可以支持不同类型(复用),且保证类型是安全的。
调用函数,什么时候可以省略泛型?
- 传入的数据可以推断出你想要的类型,就可以省略。
TS文档
TS文档:TypeScript: The starting point for learning TypeScript (typescriptlang.org)
TypeScript快速上手的更多相关文章
- 使用 Vs 2015 快速上手 Angular2
Visual Studio 2015 快速上手(使用Angular2)https://angular.cn/guide/visual-studio-2015 使用 Vs 2015 快速上手 Angul ...
- 前端开发工具包 WijmoJS 2019V1正式发布:全新的在线 Demo 系统,助您快速上手,开发无忧
前端开发工具包WijmoJS在2019年的第一个主要版本2019V1已经发布,本次发布包括了更加易用的在线Demo系统.各控件新增功能.NPM 包的改动,以及全新的浏览器API组件. WijmoJ ...
- TypeScript快速笔记(一)
刚学习TypeScript,但因为马上要用,主要是寻求先快速上手,而后再求精. 推荐学习网站: 1)https://www.runoob.com/typescript/ts-tutorial.html ...
- 十分钟快速上手NutUI
本文将会从 NutUI 初学者的使用入手,对 NutUI 做了一个快速的概述,希望能帮助新人在项目中快速上手. 文章包括以下主要内容 安装引入 NutUI NutUI 组件的使用 NutUI 主题和样 ...
- vue3快速上手
前言 虽然Vue3肯定是未来的趋势,但还不是很成熟,实际开发中用的也不多,建议学Vue3之前先掌握Vue2,将Vue3作为未来的知识储备. Vue3快速上手 Vue3简介 2020年9月18日,Vue ...
- playwright--自动化(一):快速上手
Playwright为现代 Web 应用程序提供可靠的端到端测试. 在JavaScript 和 TypeScript.Python..NET和Java 中都可以使用 Playwright 本人选择py ...
- 【Python五篇慢慢弹】快速上手学python
快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...
- 快速上手Unity原生Json库
现在新版的Unity(印象中是从5.3开始)已经提供了原生的Json库,以前一直使用LitJson,研究了一下Unity用的JsonUtility工具类的使用,发现使用还挺方便的,所以打算把项目中的J ...
- [译]:Xamarin.Android开发入门——Hello,Android Multiscreen快速上手
原文链接:Hello, Android Multiscreen Quickstart. 译文链接:Hello,Android Multiscreen快速上手 本部分介绍利用Xamarin.Androi ...
- [译]:Xamarin.Android开发入门——Hello,Android快速上手
返回索引目录 原文链接:Hello, Android_Quickstart. 译文链接:Xamarin.Android开发入门--Hello,Android快速上手 本部分介绍利用Xamarin开发A ...
随机推荐
- 制作SSL证书(签发免费证书)
制作SSL证书(签发免费证书) 下载证书生成器 wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 wget https://pkg.cfssl.org ...
- Django用户认证组件 (auth模块)
1.导入 auth 模块 # 认证模块 from django.contrib import auth # 对应数据库用户表,可以继承扩展 from django.contrib.auth.model ...
- 莫烦tensorflow学习记录 (2)激励函数Activation Function
https://mofanpy.com/tutorials/machine-learning/tensorflow/intro-activation-function/ 这里的 AF 就是指的激励函数 ...
- 6.20考试总结(NOIP模拟9)[斐波那契·数颜色·分组]
一旦你尝试过天空的味道,你就会永远向上仰望 T1 斐波那契 解题思路 题目传送门 \(70pts\)做法 这个做法比较暴力,考场上也是看到范围\(10^{12}\)后知道需要推式子,但是感觉自己太菜了 ...
- Advanced .Net Debugging 9:平台互用性
一.介绍 这是我的<Advanced .Net Debugging>这个系列的第九篇文章.这篇文章的内容是原书的第二部分的[调试实战]的第七章[互用性].互用性包含两个方面,第一个方面就是 ...
- 第二次大作业BLOG心得
(1)前言: 知识点: ①ArrayLsit的知识点: ArrayList 是 Java 中的动态数组实现,它提供了自动调整大小的功能,可以根据需要动态增长或收缩. ArrayList 可以存储任意类 ...
- Nodejs中间件 中间件分类和自定义中间件
中间件 中间件理解 中间件可以理解为业务流程的中间处理环节.如生活中吃一般炒青菜,大约分为如下几步骤 express中当一个请求到达的服务器之后,可以在给客户响应之前连续调用多个中间件,来对本次请求和 ...
- 玩转Zabbix智能告警:降噪、排班、认领、升级、IM协同
Zabbix作为一款流行的企业级监控工具,可以监控各种网络设备和服务的状态,并提供强大的告警功能,能够在出现异常情况时及时通知管理员.以下是Zabbix的一些特点: 支持多种监控方式,包括SNMP.J ...
- 前端使用 Konva 实现可视化设计器(14)- 折线 - 最优路径应用【代码篇】
话接上回<前端使用 Konva 实现可视化设计器(13)- 折线 - 最优路径应用[思路篇]>,这一章继续说说相关的代码如何构思的,如何一步步构建数据模型可供 AStar 算法进行路径规划 ...
- Scrapy框架(七)--中间件及Selenium应用
中间件 下载中间件(Downloader Middlewares) 位于scrapy引擎和下载器之间的一层组件. 作用:批量拦截到整个工程中所有的请求和响应 - 拦截请求: - UA伪装:proces ...