基本类型约束
TS是一个可选的静态的类型系统,就是说,你在.ts文件中,用和不用ts的类型检查,都没有任何关系,因为ts是js的超集
如何进行类型约束
仅需要在 变量、函数的参数、函数的返回值位置加上:类型
例如:
let num: number = 5; // 类型检查数字类型 const str: string = 'str'; // 类型检查为字符串类型 const arr:number[] = [1,2,3] // 类型检查为数字数组,对于数组来说,ts会严格检查数组里面的每一个值是否符合,不符合直接提示报错 // 类型检查一个函数,已经函数里面的形参 function add (a: number, b: number): number { return a + b; }
ts在很多场景中可以完成类型推导
- 自动推断字符串类型
let str = 'str';
- 自动推断数字类型
let age = 23;
- 自动推断函数的返回值
function add(a: number, b: number){ return a + b; }
- ts 可以在比较多的场景下,自动的推断出类型
any: 表示任意类型,对该类型,ts不进行类型检查
let a: any; a = 123; a = 'sty' a = {}
上面的代码是不是有点像我们在js里面,定义一个变量,一会儿是数字,然后是字符串,再然后是对象……,最后这个变量是啥,我们开发者自己也不清楚了。
小技巧,如何区分数字字符串和数字,关键看怎么读?
如果按照数字的方式朗读,则为数字;否则,为字符串。
源代码和编译结果的差异
编译结果中没有类型约束信息.
基本类型
- number:数字
- string:字符串
- boolean:布尔
- Array<类型>,类型:[]:数组 ,后面那一种写法是前一种的语法,一般推荐使用后面一种,因为在react中,<>代表是一个标签。
- object: 对象, 对象的检查有点弱,里面如果要严格检查里面的每一个属性,需要用到后面的接口或者类,或者是使用字面量的方式。
- null 和 undefined
null和undefined是所有其他类型的子类型,它们可以赋值给其他类型
let a: string = undefined; a = '123'; a = null;
上面的这种写法不报错,但是开发者普遍觉得都会比较乱,一会儿是字符串,一会儿是undefined,一会儿是null, 所以我们要避免这种情况。通过在tsconfig.json中添加strictNullChecks:true,可以获得更严格的空类型检查,null和undefined只能赋值给自身。
如果在代码中确实需要使用,那么我们可以使用下面的其他常用类型的联合类型就ok.
其他常用类型
- 联合类型:多种类型任选其一
配合类型保护进行判断
类型保护:当对某个变量进行类型判断之后,在判断的语句块中便可以确定它的确切类型,typeof 或者 if 可以触发类型保护,但是typeof 和 if 只能触发简单的类型保护。
//回到上面的那个在项目中确实需要使用null和undefined, 我们可以,这么写,是不会报错的。 let a: string | undefined | null = undefined; a = '123'; a = null;
- void类型:通常用于约束函数的返回值,表示该函数没有任何返回
// 形如下面这种直接在里面执行的函数,执行后没有返回值的,可以使用void来进行类型检查 function voidFunc(a: number, b: number):void{ console.log(a); console.log(b) }
当然,如果不使用void, typescript会自动的智能的推断出该函数的类型。
- never类型:通常用于约束函数的返回值,表示该函数永远不可能结束
// 形如,某些函数,永远执行都不能执行下一行的, function throwErr(msg: string):never{ throw Error(msg) console.log(msg) // 在真实的代码执行中,这一行代码永远不不可能被执行 }
- 字面量类型:使用一个值进行约束
// 这个约束特别强大,限定值的 // 例如: let sex :"男"|"女"; sex = "男" // 如果sex 为其他值,会直接报错的,因为sex就只有两个值可以选择
- 元祖类型(Tuple): 一个固定长度的数组,并且数组中每一项的类型确定
let arr:[number, string, null]; arr = [1, '2', null]; arr = [1,2,3,5]; // 这一行代码会报错 // 如下图: 数组里面的每一项都要和元组定义的类型一样,如果有任何一项不一样,那么类型检查将会通不过,直接报错。
- any类型: any类型可以绕过类型检查,因此,any类型的数据可以赋值给任意类型,不到万不得已,尽量少用
let a: string = undefined; a = '123'; a = null;
- 枚举类型: 在拓展类型里面
类型别名
对已知的一些类型定义名称
语法:
type 类型名 = ... let user: { name: string age: number sex: "男" | "女" }; // 添加用户 function addUser(user: { name: string age: number sex: "男" | "女" }) { // dosomething to add user } // 上面的代码做类型检查,我们会发现user对应的类型检查,我们会重复书写,如果将来有一天,我们的user 对象的类型需要增加或者修改一个,那么将会比较麻烦。 // 此时我们就可以使用类型别名 type User = { name: string age: number sex: "男" | "女" }; let user: User; function addUser(user: User){ // do somethong to add user } // 我们可以使用type 定义多个类型,来对对象进行详细的类型检查,或者其他的,都可以的
函数的相关约束
1.函数重载:在函数实现之前,对函数调用的多种情况进行声明
语法:
function name(参数); // 约束条件1,声明1 function name(参数); // 约束条件2,声明2 function name (参数){} // 函数实现
// 场景,我们需要使用一个函数,如果 传入的两个参数 都是 number, 求乘积,两个字符串,求字符串拼接 function contactTwo(a: number | string, b: number | string): number | string { if (typeof a === 'number' && typeof b === 'number') { return a * b; } else if(typeof a === 'string' && typeof b === 'string'){ return a + b; } throw Error('a 和 b 的类型必须相同') }
- 我们希望求乘积返回一个number,但是这个函数的结果返回值可以是number 或者 string,
- 我们希望求乘积返回一个number,但是这个函数的结果返回值可以是number 或者 string,
修改方式
// 求乘积 function contactTwo(a:number, b:number) :number; // 求字符串拼接 function contactTwo(a:string, b:string) :string; // 函数实现 function contactTwo(a: number | string, b: number | string): number | string { if (typeof a === 'number' && typeof b === 'number') { return a * b; } else if(typeof a === 'string' && typeof b === 'string'){ return a + b; } throw Error('a 和 b 的类型必须相同') }
实现的效果如下:
需要返回的number,方便类型检查
需要返回的string,方便类型检查
2.可选参数:可以在某些参数名后加上问号,表示该参数可以不用传递。可选参数必须在参数列表的末尾。
function addNum(a:number, b: number, c?:number, d?:number){ // ... 这里需要对 c 和 d 做判断, 不然类型检查会报错 return a + b + c + d; }
如果我们对函数的参数给上默认值,ts 会自动的推断,该参数是可选的类型
function addNum(a: number, b: number, c: number = 0, d: number = 0) { return a + b + c + d; }