🍦 基本类型
-类型声明
- 类型声明是TS中的一个非常重要的特点
- 同过类型声明可以指定TS中的变量(参数、形参)的类型
- 指定类型之后,当为变量赋值的时候,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错,简而言之,类型声明给变量申明了类型,就能够像强类型语言那样,指定类型的变量只能存储指定类型的值。
类型声明的语法:
let 变量: 类型;
let 变量: 类型 = value;
function f(参数: 类型, 参数: 类型): 类型{
....
}
试一试:
let kano: number = 123
console.log(kano);
结果当然是输出123了,但是如果我们之后想要把kano变量修改成'123'呢
kano = 'ddd'
console.log(kano)
当你写下这段代码的时候,编辑器马上会给你划红线,提示你不能这么做,但是你依然可以进行编译,并输出正确的结果
但是默认情况下即使有错,但也会编译成功,除非ts设置的语法检查非常严格 (后续会说明如何设置)
另外,TS中的函数是需要考虑返回值还有参数类型和个数的
function sum(a: number, b: number): number {//最后一个number其实就是函数的返回值类型
return a + b;
// return a + b + 'ddd'//返回值类型不对
}
// console.log(sum(1, '2'));//编译会报错
// sum(1,2,3)//参数多了也会报错
// sum(1)//参数少了也会报错
-自动类型判断
- TS有自动判断类型的机制
- 当对变量的声明和赋值是同时进行的时候,TS编译器会自动判断变量的类型
- 所以如果你的变量的声明和赋值是同时进行的,可以省略掉i类型声明
//TS自动类型设置
let d = false //当对变量的声明和赋值是同时进行的时候,TS编译器会自动判断变量的类型
// d = 123 //不能这么做
let e;//先声明再赋值的话,TS就不会自动判断了
e = 123 //可以这么做
e = false //可以这么做
-详细类型
类型 | 示例 | 描述 |
---|---|---|
number | 1,-1,114.514 | 任意数字 |
string | 'aa',"kano",模板字符串 |
任意字符串 |
boolean | true,false | 布尔值 |
字面量 | let a: 10; | 限制变量的值是该字面量的值(可以理解为常量) |
any | * | 任意类型 |
unknown | * | 类型安全的any |
void | 空值(undefined) | 没有值或者为undefined |
never | 没有值 | 不能是任何值 |
object | {name:'kano'} | 任意的js对象 |
array | [1,2,3,4] | 任意的js数组 |
tuple | [2,3] | 元素,TS新增类型,定长数组 |
enum | enum{A,B} | TS新增类型,枚举类型 |
number
// number
let decimal: number = 2;
let hex: number = 0x66ccff;
let binary: number = 0b1001;
let octal: number = 0o777;
let big: bigint = 100n;
字面量
字面量,可以暂时理解为常量:
//字面量,可以理解为常量
let aa: '114514';
aa = '114514'
// aa = '191981'//无法更改字面量的值
但与常量不同的是,字面量还有其他的玩法:
//可以使用 | 来连接多个类型(联合类型)
let sex: 'male' | 'female';
sex = 'male'
sex = 'female'
//sex = 'dd'//不行
当然,上面的联合类型语法也是可以用在其他地方的
let kanokano: number | string;
let kanokano1: number & string;//意思是必须同时是这两种类型,但这样写没有意义
kanokano = 1;
kanokano = '哈哈'
any
当你不想限定变量的类型时,你可以使用any摆烂:
//any
let dd: any;
dd = 111;
dd = '鸡';
dd = false;
P.S:变量没有加任何类型修饰符的情况下(且没有在定义的时候赋值),编译时默认看作any类型
但是any也不是万能的,因为any可以赋值给任意的变量,不安全
unknown
unknown是any的类型安全版本,被unknown修饰的变量不可以赋值给已经确定类型了的变量
但是其他类型的变量可以赋值给unknown修饰的变量
简而言之就是,你可以改变自己,但不可以改变别人(忽然哲学
let un: unknown;
let str: string;
un = 123;
str = '123';
// str = un; //不能赋值
str = un as string //类型断言
un = str;//可以赋值
if(typeof un === 'string'){
console.log('un变量是string类型的')
}
上面提到了 类型断言 功能,意思是告诉解析器,un是string类型的,下方细说
类型断言
类型断言:可以用来告诉解析器变量的实际类型
语法:变量 as 类型
或者 <类型>变量
let dy: unknown;
let str2: number;
dy = 123;
// str2 = dy as number;
str2 = <number>dy;
看上去非常像强类型语言里面的泛型 or 强制转换,其实不然,让我们看下面的例子
let dy: unknown;
let str2: number;
dy = 'ddd';
str2 = dy as number;
// str2 = <number>dy;
console.log(str2)
上面执行没有问题,输出ddd,这是因为类型断言只是在欺骗编译器,让编译器误认为可以编译通过
这一点是区别于强制类型转换的
void
如果函数的返回值没有意义的话,可以用void来修饰返回值,return的时候可以写null也可以写undefined
//可以返回undefined或者null
function fn1(): void{
return null
}
never
一个函数如果返回值用never修饰的话,就不能有任何return了,但是可以在函数体内抛出异常
当这个函数被调用的时候,就会抛出一个异常:
//不能有return ,用never修饰函数就是专门用来抛出错误的
function fn2(): never{
throw new Error('这是一个报错');
}
object
首先说明一下,object修饰符实际开发中很少使用,因为它不能明确的指定是对象还是其他的引用类型
let obj: object;
obj = {}
obj = () => null
但是有一个更好用的对象修饰符 {}
{}用来指定对象中的必选属性、属性类型
语法:{属性名:属性类型}
可选属性:{属性名?:属性类型}
下面表示obj2是一个对象,属性值a是必选,age是可选,
let obj2:{a:string,age?:number}
obj2= {a:'dd'}
但上面的对象并不能支持任意多个属性的清空,所以我们还可以使用索引签名让对象开放任意个数的属性限制
//propName:string 表示属性名为string类型,这里可以选 string number或者symbol或者模板文本类型
let obj3:{b:string,[propName:string]:any}
obj3 = {b:'dd',c:'23',d:123}
函数类型
如果你希望一个变量只能保存函数的话,可以这么写
设置函数结构的类型声明
语法 (形参:类型,形参1:类型,....) => 返回值
let d2: (a: number, b: number) => number //变量名是什么无所谓
d2 = function (n1, n2): number {
return n1 + n2
}
数组
TS中,我们可以声明一个类型确定的数组,以便于存放固定类型的值
let ee: string[]
ee = ['1','a',"hello"]
let num: number[]
num = [1,2,3,4,5,6]
//这种写法也是可以的
let kano11:Array<number>
元组
其实就是固定长度的数组
let hh: [string, string]
hh = ['111', 'ddd']
枚举类型
和其他语言的枚举基本一样
enum Gender {
Male,
Female
}
//使用枚举就可以方便代码管理者,不用去特意知道男是1还是女是1了
let i: { name: string, gender: Gender }
i = {
name: 'kano',
gender: Gender.Female
}
类型的别名
我们可以给预定义的类型起一个自己的别名
type myType = string;
type myType2 = 1|2|3;
let k: myType;
let l: 1|2|3;
let m: myType2;
l = 1 //正确
//l = 4 //错误
补充
在字面量小结有提到 let kanokano1: number & string
这段代码,这段代码是没有意义的,因为变量不可能同时是number类型和string类型,那这个& 符号有什么用呢?其实可以这样用:
let jj: {name:string} & {gender:Gender}
jj = {name: 'kano',gender: Gender.Female}
上面的jj对象,可以链接两个对象类型,意思是必须要有name和gender属性