Enums 枚举
枚举在程序语言及 mysql 等数据库中广泛使用
- 不设置值时,值以 0 开始递增
下面是使用枚举设置性别
enum SexType {
boy,
girl
}
const obj = {
name: 'hj',
sex: SexType.boy
}
console.log(obj); // { name: 'hj', sex: 0 }
console.log(SexType.girl); // 1
- 当某个字段设置数值类型的值后,后面的在它基础上递增
enum SexType {
boy = 1,
girl
}
const obj = {
name: 'hj',
sex: SexType.boy
}
console.log(obj); // { name: 'hj', sex: 1 }
console.log(SexType.girl); // 2
- 可以将值设置为其他类型
enum SexType {
boy = '男',
girl = '女'
}
const obj = {
name: 'hj',
sex: SexType.boy
}
console.log(obj); // { name: 'hj', sex: '男' }
console.log(SexType.girl); // 女
as 断言
as 断言的意思就是用户断定这是什么类型,不使用系统推断的类型,说白了就是 我说是什么,就是什么
下例中 TS 会根据函数推断变量 data 的类型是 string | number
const hj = (a: boolean) => {
return a ? 'hj' : 18
}
let data = hj(true) // let data: string | number
我们可以由开发者来断定(断言)这就是字符串,这就是断言
const hj = (a: boolean) => {
return a ? 'hj' : 18
}
let data = hj(true) as string // let data: string
也可以使用下面的断言语法
const hj = (a: boolean) => {
return a ? 'hj' : 18
}
let data = <string>hj(true) // let data: string
const 断言
let & const
- const 保证该字面量的严格类型
- let 为通用类型比如字符串类型
const hj = 'hj' // const hj: "hj"
let hk = 'hj' // let hk: string
const
const
断言告诉编译器为表达式推断出它能推断出的最窄或最特定的类型,而不是宽泛的类型
- 字符串、布尔类型转换为具体值
- 对象转换为只读属性
- 数组转换成为只读元组
下面限定 user 类型为最窄类型 hj
let user = 'hj' as const
user = 'hk' // 不能将类型“"hk"”分配给类型“"hj"”
// 与以下很相似
let user: 'hj' = 'hj'
user = 'hk' // 不能将类型“"hk"”分配给类型“"hj"”
对象转换为只读属性
let hj = {name: 'hj', age: 18} as const
hj.name = 'hk' // 无法分配到 "name" ,因为它是只读属性
当为变量时转换为变量类型,具体值是转为值类型
let a = 'a'
let b = 'b'
let hj = [a, b, 'hj', 18] as const // let hj: readonly [string, string, "hj", 18]
hj[0] = 'c' // 无法分配到 "0" ,因为它是只读属性
数组赋值
变量 f 得到的类型是数组的类型 string|number,所以只要值是这两个类型都可以
let a = 'hj'
let b = 18
let hj = [a, b] // let hj: (string | number)[]
let c = hj[1] // let c: string | number
c = 'hk' // 不报错,因为类型是 string | number
使用 const 后会得到值的具体类型,而不是数组的类型
let a = 'hj'
let b = 18
let hj = [a, b] as const // let hj: readonly [string, number]
let c = hj[1] // let c: number
c = 'hk' // 报错,不能将类型“string”分配给类型“number”
也可以使用以下语法
let a = 'hj'
let b = 18
let hj = <const>[a, b] // let hj: readonly [string, number]
let c = hj[1] //let c: number
c = 'hk' // 报错,不能将类型“string”分配给类型“number”
解构
下面解构得到的变量类型不是具体类型,而是数组类型,比如变量 y 的类型是 string | (() => void)
这在写项目时是不安全的,因为可以将 y 随时修改为字符串,同时也不会有友好的代码提示
function hj() {
let a = 'hj'
let b = (x: number, y: number): number => x + y
return [a, b]
}
let [n, m] = hj() // 变量 m 的类型为 string | (() => void)
m(1, 6) // 报错:因为类型可能是字符串,所以不允许调用
可以断言 m 为函数然后调用
function hj() {
let a = 'hj'
let b = (x: number, y: number): number => x + y
return [a, b]
}
let [n, m] = hj()
console.log((m as Function)(1, 2))
// 使用以下类型声明都是可以的
console.log((m as (x: number, y: number) => number)(1, 5)
可以在调用时对返回值断言类型
function hj() {
let a = 'hj'
let b = (x: number, y: number): number => x + y
return [a, b]
}
let [n, m] = hj() as [string, (x: number, y: number) => number]
console.log(m(9, 19))
也可以在函数体内声明返回类型
function hj() {
let a = 'hj'
let b = (x: number, y: number): number => x + y
return [a, b] as [typeof a, typeof b]
}
let [n, m] = hj()
console.log(m(9, 19))
使用 as const 就可以很高效的解决上面的问题,可以得到具体的类型,来得到更安全的代码,同时会有更好的代码提示
function hj() {
let a = 'hj'
let b = (): void => {}
return [a, b] as const
}
const [x, y] = hj() // 变量 y 的类型为 () => void
因为 const 是取值的类型,下面代码虽然不报错,但此时 b 的类型已经是 字符串或函数,所以像下面一样在函数调用时 as const 没有意义
function hj() {
let a = 'hj'
let b = (x: number, y: number): number => x + y
return [a, b]
}
const [n, m] = [...hj()] as const
非空断言
下面的示例获取的值可能为 HTMLDivElement 或 null,所以直接分配类型“HTMLDivElement”将报错误
下例操作需要开启 tsconfig.json 的配置项 strictNullChecks 字段为 true
const el: HTMLDivElement = document.querySelector('.hj')
console.log(el.id);
可以使用 as 断言类型
const el: HTMLDivElement = document.querySelector('.hj') as HTMLDivElement
console.log(el.id);
在值后面使用 !
来声明值非 null
const el: HTMLDivElement = document.querySelector('.hj')!
console.log(el.id);
DOM
为了演示示例我们创建 html 文件如下
- 下面的操作需要开启 tsconfig.json 的配置项 strictNullChecks 字段为 true
<!DOCTYPE html>
<html lang="en">
<head>
<title>TS</title>
<script src="1.js" defer></script>
</head>
<body>
<div class="hj">ts</div>
<button id="bt">插入元素</button>
</body>
</html>
类型推断
对于获取的标签对象可能是为 null 也可能是该标签类型
- body 等具体标签可以准确标签类型或 null
- 根据 class 等获取不能准确获取标签类型,推断的类型为 Element | null
const body = document.querySelector('body') // const body: HTMLBodyElement | null
下面是根据 class 获取标签结果是 ELement 并不是具体的标签,因为根据 class 无法确定标签类型
const el = document.querySelector('.hj') // const el: Element | null
断言处理
使用as
将类型声明为 HTMLAnchorElement
则 TS 会将其按 a 链接类型处理
- 现在所有的提示将是 a 链接属性或方法
const el = document.querySelector('.hj') as HTMLAnchorElement // const el: HTMLAnchorElement
console.log(el.href);
下例中的 DOM 类型会报错,因为.hj 是 Element 类型,而构建函数参数 el 的类型是 HTMLDivElement
class Hj {
constructor(el: HTMLDivElement) {
}
}
const el = document.querySelector('.hj'); // el: Element
new Hj(el)
这时可以使用 as 断言处理,明确告之获取的值类型是 HTMLDivElement
class Hj {
constructor(el: HTMLDivElement) {
}
}
const el = document.querySelector('.hj') as HTMLDivElement;
new Hj(el)
事件处理
下面提取按钮元素并添加事件,实现插入元素的功能
const hj = document.querySelector('#hj') as HTMLButtonElement
hj.addEventListener('click', (e: Event) => {
e.preventDefault() // 因为设置了 e 的类型,所以会有完善的提示
console.log(e);
})