-
目录
interface (接口)和type (类型别名)的对比:【重点】
可以将TS 中的常用基础类型细分为两类:
1)、JS 已有类型
JS已有型: 原始类型:number/string/boolean/null/undefined/symbol. 对象类型: object (包括,数组、对象、函数等对象)。
2)、TS 新增类型:
TS 新增类型 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、 void、any等。
-
类型声明
-
类型声明是TS非常重要的一个特点
-
通过类型声明可以指定TS中变量(属性、形参)的类型
-
指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错
-
简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值
-
语法:
let 变量: 类型; let 变量: 类型 = 值; ==> 简写:let 变量 = 值; let 变量 = 值; function fn(参数: 类型, 参数: 类型): 类型{ ... }
-
-
自动类型判断
-
TS拥有自动的类型判断机制
-
当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
-
所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明
-
-
类型:
类型 例子 描述 number 1, -33, 2.5 任意数字 string 'hi', "hi", hi
任意字符串 boolean true、false 布尔值true或false 字面量 其本身 限制变量的值就是该字面量的值 any * 任意类型,没有类型校验 unknown * 安全的any类型 void 比如没有返回值的函数,其返回值类型为 void |undefined 表示没有任何类型 never function foo():never { throw new Error('我是一条错误信息') } 永远不会有值的一种类型,任何类型都不能赋值给 never 类型的变量,只能never=never object {name:'孙悟空'} 任意的JS对象 array [1,2,3] 任意JS数组 tuple [4,5] 元组,TS新增类型,固定长度数组 enum enum{A, B} 枚举,TS中新增类型 -
string
let username: string //定义类型不赋值 username = "李四" // username = 12//不能将类型“number”分配给类型“string”。 let hopy: string = "篮球"//定义类型并赋值 let sex = "男"//定义变量并赋值(TS类型自动推断) // sex = 20;//不能将类型“number”分配给类型“string”。
-
number
let userage: number = 20 // userage = "12"//不能将类型“string”分配给类型“number”。 let big: bigint = 100n;
-
boolean
let isShow:boolean=true
-
字面量
字面量(自定义变量类型):变量的值必须和自定义变量类型值一致
也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围
let age:18 = 18 let work: "web" // work = "ui"//不能将类型“"ui"”分配给类型“"web"”。 work = "web" // 字面量配合联合类型使用 let live: 0 | 1 | 2 // live=3//不能将类型“3”分配给类型“0 | 1 | 2”。 live=1
-
any
注意:不推荐使用
//任何类型 没有类型校验 let obj: any obj = 123 obj = "123" obj = true // 如果变量声明了但是没有设置类型和赋值 默认类型就是any let obj2; obj2 ="123" obj2 = 123 // 可以将any类型的数据直接赋值给其他变量 不够安全 let username: string username = obj
-
unknown
当一个值被标记为
unknown
类型时,它只能赋值给unknown
或any
类型。这意味着我们不能对unknown
类型的值执行任何操作,除非我们首先进行类型检查或类型断言。// unknown 未知类型 安全的any类型 let obj3: unknown obj3 = 123 obj3 = "123" let value: unknown; value = 5; // 正确,可以将数字赋值给 unknown 类型 value = 'Hello'; // 正确,可以将字符串赋值给 unknown 类型 value = true; // 正确,可以将布尔值赋值给 unknown 类型 let value1: unknown = value; // OK let value2: any = value; // OK let value3: boolean = value; // Error let value4: number = value; // Error let value5: string = value; // Error let value6: object = value; // Error let value7: any[] = value; // Error let value8: Function = value; // Error // 进行类型检查 if (typeof value === 'number') { let num: number = value; // 正确,因为在此分支中,value 已被确定为 number 类型 } // 进行类型断言 let strLength: number = (value as string).length; // 正确,使用类型断言将 value 断言为 string 类型,并获取其长度 // username = obj3//不能将类型“unknown”直接分配给类型“string” // 可以通过类型断言赋值给其他变量 username = obj3 as string//写法1 username = <string>obj3//写法2
-
void
// void 空值(undefined) 没有任何类型 常用于没有返回值的方法 let v1: void // v1 = 123//不能将类型“number”分配给类型“void”。 v1 = undefined // function f1(): void { return 123}//不能将类型“number”分配给类型“void”。 //如果函数没有返回值,那么,函数返回值类型为: void function getInfo(): void { console.log('我只是一段代码逻辑,没有返回值!') } getInfo()
-
never
// never 永远不会有值的一种类型 let v2: never // v2 = undefined//不能将类型“undefined”分配给类型“never”。 // 一个从来不会有返回值的函数,即死循环 function xun(): never { while (true) { } } // 一个总是会抛出错误的函数 function foo():never { throw new Error('我是一条错误信息') } // foo()
-
never VS void
// void 表示没有任何类型,never 表示永远不存在的值的类型。 // 返回never的函数必须存在无法达到的终点 function infiniteLoop(): never { while (true) { } } // 这个函数不能申明其返回值类型是 never function warnUser(): void { console.log("This is my warning message"); }
-
object
// object 语法:object | {} let v3: object // v3 = 12//不能将类型“number”分配给类型“object”。 v3 = { id: 11, name: "李四" } //限制每个字段类型 let v33: { name: string, age: number } v33 = { name: "李四", age: 20 } //设置对象中除了默认属性外的冗余属性 let v333: { id: number, [propName: string]: any } v333 = { id: 1, name: "李四", age: 20 }
-
array
// array 语法:类型[] | Array<类型> let v4: number[] //推荐使用这种写法 // v4 = "你好"//不能将类型“string”分配给类型“number[]”。 let v5: Array<number> // v5 = ['1','2']//不能将类型“string”分配给类型“number”。 v5 = [1, 2] let v6: any[] v6 = [{},1,"李四"]
-
tuple
场景:在地图中,使用经纬度坐标来标记位置信息。
可以使用数组来记录坐标,那么,该数组中只有两个元素,并且这两个元素都是数值类型。
let position: number ] = [36.54,118.17]
使用 numbel] 的缺点: 不严谨,因为该类型的数组中可以出现任意多个数字。 更好的方式:元组 (Tuple)。 元组类型是另一种类型的致组,它确切地知道包含多少个元素,以及特定索引对应的类型。
let position: [number, number] = [36.54,118.17]
解释:
//元组tuple 固定长度的数组 语法:[类型,类型.....] let v7: [number, string, object] v7 = [1, "web", { name: "鲁班" }]
-
元组类型可以确切地标记出有多少个元素,以及每个元素的类型
-
该示例中,元素有两个元素,每个元素的类型都是number。
-
-
enum
枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值
枚举:定义一组命名常量。它措述一个值,该值可以是这些命名常量中的一个
// 枚举类型 语法:enum value{v1,v2} // 联合类型写法 不清楚 数字具体是什么意思? let orderStatus: 1 | 2 | 3 orderStatus = 1 // 使用枚举优化解决 enum orStatus { "代付款"=1, "代发货"=2, "代收货"=3 } let goodStatus: orStatus goodStatus = orStatus.代付款 console.log(goodStatus)
-
类型别名
类型别名 (自定义类型): 为任意类型起别名。
使用场景:当同一类型被多次使用时,可以通过类型别名,简化该类型的使用。
// 类型别名 语法: type value: type CustomArray = (number | string)[] let arr1:CustomArray = [1,'a',33] let arr2:CustomArray = [99,80,'ok'] type color = "绿色" | "红色" | "蓝色" let textColor: color textColor = "红色"
-
函数
// 15.函数 关心其参数类型和返回值类型
function fn(age: number, name: string): void {
console.log(`用户姓名是${name}--年龄是:${age}`)
}
// fn("12","李四")//类型“string”的参数不能赋给类型“number”的参数。
fn(12,"李四")
使用函数实现某个功能时,参数可以传也可以不传。这种情况下,在给函数参数指定类型时,就用到可选参数
比如,数组的 slice 方法,可以slice() 也可以 slice(1) 还可以 slice(1,3)。
function mySlice(start?: number, end?: number): void { console.log("起始索引: ,start,结束索引:end) }
可选参数:在可传可不传的参数名称后面添加?(问号)
注意:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数。
-
类型推论 【重点】
在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型,也就是说: 由于类型推论的存在,这些地方类型注解可以省略不写。发生类型推论的 2种常见场景:
1) 声明变量并初始化时
2) 决定函数返回值时
//let age:number = 18
let age = 18 //TS自动推断出变量 age 为 number 类型
//function add(num1: number, num2: number):number {return num1 + num2 }
function add(num1: number, num2: number) {return num1 + num2 }
注意:这两种情况下,类型注解可以省略不写!
推荐:能省略类型注解的地方就省略(这样充分利用TS类型推论的能力,提升开发效率)
-
类型断言【重点】
// 类型断言 语法: prop as type | <type>prop const obj = {} //obj.tel = 110 //错误:Property 'tel' does not exist on type '{}'. //类型别名: type objType = { tel:number, goods:string } //const obj2 = {} as objType; // 类型断言 写法一 const obj2 = <objType>{}; // 类型断言 写法二 obj2.tel = 110; let v8: unknown v8 = [1, 2, 3] let v9: number //当v8是数组的时候获取其长度赋值v9 v9 = (v8 as any[]).length v9 = (<any[]>v8).length
-
有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式:
-
-
接口
当一个对象类型被多次使用时,一般会使用接口 (interfaxe) 来描述对象的类型,达到复用的目的。
// 接口 interface 语法:interface{}
// 接口可以去限制一个对象的结构,对象只有包含接口中定义的所有属性和方法时才能匹配接口。
let v10: {name:string,age:number}
// 定义接口规范对象数据内容(项目中常用)
interface userInfo {
name: string,
age: number,
[propName:string]:any
}
// 测试
let v11: userInfo
v11 = { name: "李四", age: 18, hopy: "篮球" }
// 项目实际应用:
let data = {
list: [] as userInfo[],
all:<userInfo[]>[]
}
data.list = [{ name: "张三", age: 18 }]
-
interface (接口)和type (类型别名)的对比:【重点】
相同点: 都可以给对象指定类型
不同点: 接口,只能为对象指定类型。 类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名
interface Persons {
name: string
age: number
sayHi(): void
}
type Persons2 = {
name: string
age: number
sayHi(): void
}
type NumStr = number l string
-
typeof
JS 中提供了 typeof 操作符,用来在JS 中获取数据的类型。
console.log(typeof"Hello WEB") // f印 string
TS 也提供了 typeof 操作符: 可以在类型上下文中引用变量或属性的类型(类型查询)
使用场景:根据已有变量的值,获取该值的类型,来简化类型书写。
let p = {x: 11,y: 22} function myPoint(point: {x:number, y:number}) {} myPoint(p)
可以这样来写:
let p = {x: 11,y: 22} function myPoint(point: typeof p){} myPoint(p)
说明:
1).使用 typeo 操作符来获取变量 p 的类型,结果与第一种(对象字面量形式的类型)相 同;
2).typeof 出现在类型注解的位置(参数名称的冒号后面) 所处的环境就在类型上下文;
3). 注意:typeof 只能用来查询变量或属性的类型,无法查询其它形式的类型(比如,函数调用的类型)。
-
? 和 !
? 表示变量是可选的
//接口对子类对象具有强制性 interface DB { name: string age?: number // ? 表示 age属性是可选的 } function myDB(db: DB) { } myDB({ name:"悟空”})
! 为非空断言运算符
//实例一: let a :string | null |undefined let b :string b=a //错误 b=a!//正确,a!表示a排除null undefined类型 //实例二: function myFun(maybeString: string | undefined | null) { const onlyString: string = maybeString; //错误 const ignoreUndefinedNull:string = maybeString!; //正确 }