一、类型系统
类型系统有两种,如下:
显式注解类型
告诉编辑器所有值的类型
const a:number = 1 // a是一个数字
const b:string = 'hello' // b是一个字符串
自动推导类型
自动推导值的类型
const a = 1 // a是一个数字
const b = 'hello' // b是一个字符串
一般来说,最好让ts推导类型,少数情况下才显式注解类型
二、并集类型与交集类型
并集类型
并集类型 type1 | type2 ,表示要么满足type1,要么满足type2,要么同时满足type1和type2,否则会波浪线提示
interface objI {
name: string,
age: number
}
interface objI2 {
name: string,
sex: boolean
}
// 并集类型使用
let obj: (objI | objI2) = {
name: '正常执行',
age: 12
}
obj = {
name: '正常执行',
sex: true
}
obj = {
name: '正常执行',
sex: true,
age: 12
}
obj = {
name: '我不能满足objI,也不能满足objI2,所以我也会波浪线提示'
}
obj = {
name: '正常执行',
sex: true,
age: 12,
asdf: '我是objI和objI2都不存在的属性,所以我会波浪线提示'
}
交集类型
交集类型type1 & type2,表示必须同时满足type1和type2
interface objI {
name: string,
age: number
}
interface objI2 {
name: string,
sex: boolean
}
let obj: (objI & objI2) = {
name: '正常执行',
age: 12,
sex: true
}
obj = {
name: '我不能满足typeI, 只满足typeI2,所以会波浪线提示',
sex: true
}
obj = {
name: '我不能满足objI,也不能满足objI2,所以我也会波浪线提示'
}
obj = {
name: 'name',
sex: true,
age: 12,
asdf: '我是objI和objI2都不存在的属性,所以我会波浪线提示'
}
三、类型浅谈
any
any包含所有的值,可以对其做任何操作,尽量避免使用。
let a:any = 666
let b:any = ['danger']
let c = a + b // 正常这样会报错,但是设置类型为any后,这里并不会报错
unknown
与any类似,也表示任何值,但是ts会要求你再做检查,细化类型。
const a:unknown = 1
// const b = a + 10 // 会红色波浪线提示,运算符+不能用于unknown和10
if (typeof a === 'number') { // 提前判断下,下方才不会报错
const b = a + 10
}
boolean
总共有两个值:true和false
let a = true // boolean
let b:boolean = true // boolean
// 可以明确的告诉ts,该值为某具体的布尔值
const c = true // true
const d:true = true // true
const e:true = false // 会波浪线提示
// c = false // 波浪线提示,c是一个常数,不可修改
a = false // 正常执行
number
同js,包括所有的数字(注意,大于2的53次方的数字,精度可能会丢失)
let a = 2
a = '2' // 会波浪线提示,字符串不可赋值给number
let a = 9999999999999999
console.log('-------->', a, 2**53) // 10000000000000000 9007199254740992 a的精度丢失少了1
bigint
bigint是js和ts新引入的类型,在处理较大整数(超出2的53次方时)时,不用再担心舍入误差。
let a = 9999999999999999n
console.log('-------->', a) // 9999999999999999n
string
同js,也可以明确指定具体值
let a: 'john' = 'zoe' // 波浪线提示
let b: 'john' = 'john' // 正常执行,同const
b = 'zoe' // 波浪线提示
symbol
符号,不太常用
对象
object (注意o是小写的)
object仅比any的范围窄一些,但也窄不了多少,object对值知之甚少,只能表示该值是一个javaScript对象
let danger:object = {}
danger = null // 正常执行
danger = undefined // 正常执行
danger = { x: 1 } // 正常执行
danger = [] // 正常执行
danger = 2 // 波浪线提示
danger = '我是字符串' // 波浪线提示
let a: object = {
b: 'x'
}
console.log(a.b)
会波浪线提示
如果不显式注解,ts会主动推导对象的结构,也可以在{}里明确描叙
let a = {
b: 'x'
}
let c: {d: string} = {
d: 'x'
}
console.log(a.b)
console.log(c.d)
前面有说const会对推导结果有影响,object不同,const并不会导致ts把推导的类型缩窄,这是因为js对象是可变的,所以在ts看来,创建对象后,你可能会更新对象的字段
const a = {
b: 'x'
}
a.b = 'y' // 正常执行
const b = 2
b = 3 // 会波浪线提示
告诉ts某个属性是可选的,加修饰符?
let c: { d: string, e: number } = {
d: 'x'
} // 会波浪线提示,因为e是必选的属性
let d: { d: string, e?: number } = {
d: 'x'
} // 正常执行,因为e后面加了个可选标志,所以e是可有可无的
告诉ts实际属性比计划的多
interface aI {
b: number,
[key: string]: boolean | number
}
let a: aI = {
b: 1,
d: true, // 多了d属性,正常执行
e: '我是string, 这里会波浪线提示,因为[key: string]: boolean | number 里定义好了,只能为boolean和number'
}
[key: T]: U 这种写法叫索引签名,key可以为任意值,T必须可赋值给number或string,U的类型中必须包含整个object里的所有类型 修饰符readonly
interface objI {
readonly b: string
}
let obj: objI = {
b: '1'
}
obj.b = '我会波浪线提示,因为我是readonly,不可修改'
空对象类型{}
任何类型都可以赋值给空对象类型,比object(o小写)还要宽些,尽量避免使用该类型
let danger = {}
danger = null
danger = undefined
danger = { x: 1 }
danger = []
danger = 2
danger = '此块代码全部正常执行'
Object(注意O是大写的)
同{},尽量避免使用
数组
ts支持两种注解数组类型的语法:T[]和Array<T>,两者的作用等同
let a: Array<number> = [1]
let b: number[] = [1]
元组
元组是数组的子类型,是定义数组的一种特殊方式,长度固定,各索引位上的值具有固定的已知类型
let a: [number, string] = [1, '我是固定长度为2的元组,不能超过这个长度,否则会波浪线提示']
let b: [number, string?] = [1, '我是可选的元素,所以此元组的长度可以为1,也可以为2']
let c: [string, boolean, ...string[]] = ['a', true, '元组支持剩余元素,即为元组定义最小长度,且剩下的其他元素类型定义为string']
enum
枚举,和object很像,但不可修改
// 注意首字母要大写
const enum Meijun {
Color = 'red',
Size = '24px'
}
let b = Meijun.Color // Meijun red
b = '会波浪线提示,因为不可修改,只能读取Meijun里的值'
其他类型
null: 缺少值
undefined:尚未赋值的变量
void: 没有return语句的函数
never:永不返回的函数(基本不用)
function a() {
return '这是一个返回string的函数,隐式注解'
}
function aa():string {
return '这是一个返回string的函数, 显式注解'
}
function b() {
const str = '这是一个返回void的函数,隐式注解'
}
function bb() {
const str = '这是一个返回void的函数,显式注解'
}
function c(): never {
throw TypeError('这是一个返回never的函数')
}
function d(): never {
while (true) {
console.log('这是一个返回never的函数')
}
}
四、函数
1、声明和调用函数
多数情况下,ts无法推导出参数的类型,因此,我们会显示注解函数的参数。其余同js.
const fun = (a: number, b: number) => {
return a*b
}
返回类型能推导出来,不过也可以显示注解
const fun = (a: number, b: number): number => {
return a*b
}
可选和默认的参数
和object一样,可以使用修饰符?标记参数为可选的,申明参数时,必要的参数放前面,可选的放后面
const fun = (a: string, b?: string) => {
return a || b
}
fun('我是必传的参数,不传会波浪线提示', '可选参数,传或不传,都不会提示')
const fun = (a: string = '虽然我是必传的参数,但是我有默认值,所以下方不传,也不会波浪线提示', b?: string) => {
return a || b
}
fun()
剩余参数
参数的具体数量无法确定,此时需要用剩余参数
// 错误示例:
(() => {
const fun = (a: string, ...arguments) => {
console.log('==========>', a, ...arguments)
}
fun('使用js的剩余参数方法,虽然此时不会此时不会波浪线提示,但是在运行时,会报错', 2)
})()
// 正确示例:
const fun = (a: number, ...numbers: number[]) => {
console.log('==========1>', a, numbers)
}
// 函数调用
fun(1, 2, 3)
函数调用
const fun = (a: string, ...numbers: number[]) => {
console.log('==========1>', a, ...numbers)
}
fun('我是圆括号调用,最常用的调用方法', 1)
fun.apply(null, ['apply调用,为函数内部的this绑定一个值,然后展开第二个参数(数组形式),传给要调用的函数', 2])
fun.call(null, ['call调用,和apply类似,不过是按照顺序应用参数,而不做展开', 3])
fun.bind(null, ['bind调用,和call类似,不过并不调用函数,而是返回一个新的函数,让我们继续用上方方法去调用', 4])()
持续更新中。。。