变量后面约定类型的语法,就是类型注解
作用: 约定类型,明确提示
// 类型注解
let age:number = 18;
age = 19;
// age = "hello"; //不能将类型“string”分配给类型“number”
TS常用类型:
// 数组类型
// 第一种写法【推荐】
let numbers:number[] = [1,2,3];
// 第二种写法
let strings:Array = ["a","b","c"];
将多个类型合并为一个类型
类型和类型之间使用 | 连接,代表类型可以是他们当中的其中一种,这种类型叫联合类型
// 数组中有number 和string 如何写?
let arr:(number | string |boolean)[] = [1,"hello",4,"456",true];
// 给定时器加类型
let timer:number | null = null;
timer= setInterval(()=>{},1000)
使用类型别名语法给类型重新起名字
当同一类型被多次使用时,可以通过类型别名,简化该类型的使用
// 类型别名
// let arr1:(number|string|boolean)[] =[1,2,"hello"];
// 类型别名 type 类型别名 = 具体类型
type CustomArr = (number | string | boolean)[];
let arr1:CustomArr = [1,2,"hello",true];
给函数指定类型,就是给 参数和返回值 指定类型
两种写法:
- 在函数基础上 分别指定 参数和返回值类型
- 使用类型别名 同时指定 参数和返回值的类型
// - 在函数基础上 **分别指定** 参数和返回值类型
// 函数声明
function add(num1:number,num2:number):number{
return num1 + num2
}
console.log(add(1,2));
// 箭头函数
const add1 = (num1:number,num2:number):number=>{
return num1 + num2;
}
console.log(add1(3,4))
// - 使用类型别名 **同时指定** 参数和返回值的类型
//只适用于函数表达式
type AddFn = (num1:number ,num2:number) =>number
const add2:AddFn =(num1,num2)=>{
return num1 + num2;
}
console.log(add2(7,8));
void函数返回值类型
如果函数没有返回值,定义函数类型时返回值类型为void
如果函数没有返回值,且没有定义函数返回值类型的时候,默认是void
// void类型
// 如果函数没有返回值,定义函数类型时返回值类型为void
const say = ():void=>{
console.log("hi");
}
say()
// 如果函数没有返回值,且没有定义函数返回值类型的时候,默认是void
const say1 = ()=>{
console.log("hhi");
}
say1()
// 如果指定返回值类型是undefined 那返回值必须是undefined
const add4 = ():undefined=>{
return undefined;
}
使用 ? 将参数标记为可选
如果函数的参数,可以传也可以不传,这种情况就可以使用 可选参数 语法,参数后加 ? 即可
const fn = (n?:number)=>{
console.log(123)
}
fn();
fn(3);
案例
// 模拟slice函数, 定义函数参数类型
// 注意:必须参数不能位于可选参数后面
const mySlice = (start:number,end?:number) =>{
console.log("起始index"+start+'结束index'+end)
}
mySlice(2)
mySlice(4,5)
TS的对象类型,其实就是描述对象中的属性 方法的类型,因为对象是由属性和方法组成的
// 空对象
let person:{} = {}
// 有属性的对象
let person1:{name:string} = {
name:"zs"
}
// 有属性和方法,一行书写多个属性 ; 分割
let person2:{name:string;sayHi():void} = {
name:"jack",
sayHi(){}
}
// 换行写 可以省略 ; 符号
let person3 :{
name:string
sayHi():void
} = {
name:"zs",
sayHi(){}
}
对象类型中,函数使用箭头函数类型,属性设置可选,使用类型别名
函数使用箭头函数类型
let person5:{
name:string
sayHi:()=>void
} = {
name:"jack",
sayHi(){}
}
对象属性设置可选
// axiois({url,method}) 如果是get 请求method 可以省略
const axios =(config:{url:string;method?:string})=>{}
使用类型别名
// { } 会降低代码可阅读性,建议对象使用类型别名
type Config = {
url:string;
method?:string
}
const axios1 =(config:Config) =>{}
使用interface声明对象类型
接口声明是命名对象类型的另一种方式
// 接口 interface声明对象类型
interface Person{
name:string;
age:number;
sayHi:()=>void
}
// 使用类型
let person8:Person = {
name:"zs",
age:12,
sayHi(){}
}
使用extends实现接口继承,达到类型复用
语法:interface 接口A extends 接口B { }
继承后接口A拥有接口B的所有属性和函数的类型声明
// interface 继承
// 有两个接口,有相同的属性或函数,如何提高代码复用?
// interface Point2D {
// x:number;
// y:number;
// }
// interface Point3D {
// x:number;
// y:number;
// z:number;
// }
// 继承 相同的属性或方法可以抽离出来,使用extends实现继承复用
interface Point2D {
x:number;
y:number;
}
// 继承Point2D
interface Point3D extends Point2D {
z:number;
}
let p:Point3D ={
x:12,
y:23,
z:56
}
交叉类型实现接口的继承效果
使用 & 可以合并连接的对象类型 叫做交叉类型
// type交叉类型
// 使用type来定义Point2D 和Point3D
type Point2D = {
x:number;
y:number;
}
// 使用交叉类型 来实现接口继承的功能
type Point3D =Point2D & {
z:number;
}
let o:Point3D= {
x:1,
y:2,
z:3
}
interface | type |
---|---|
支持:对象类型 | 支持:对象类型 其他类型 |
复用: 可以继承 | 复用: 交叉类型 |
不同点
type Point2D = {
x:number;
y:number;
}
// 标识符“Point2D”重复
type Point2D = {
age:number;
}
//-------------------------------------
interface Point2D {
x:number;
y:number;
}
//类型会合并 注意:属性类型和方法类型不能重复定义
interface Point2D {
age:number
}
// 继承Point2D
interface Point3D extends Point2D {
z:number;
}
let p:Point3D ={
x:12,
y:23,
z:56,
age:78
}
开发项目时,能省略类型注解的地方就省略, 充分利用TS的类型推断能力,提高开发效率
// 发生类型推断的几个场景
// 变量a的类型被自动推断为 number
let a = 18;
// 函数的返回值类型被自动推断为 number
const add3 = (num1:number,num2:number) =>{
return num1 + num2
}
js字面量如: 18 ‘jack’ [‘a’] {age:10} 等等
使用js字面量作为变量类型,这种类型就是字面量类型
// 'lucy' 是字面量类型
let n:'lucy' = 'lucy';
// 18 是字面量类型
let n1:18 = 18;
// 报错 不能将类型“19”分配给类型“18”
// n1 = 19;
let str1 = "hello"; //str1的类型是string
const str2 = "hello"; //str2的类型是 "hello" str2是const声明的 值只能是 "hello"
// 性别只能是男 和 女 不会出现其他值
// let gender = '男';
// gender = '女'
// 字面量类型 配合联合类型使用, 表示 一组明确的可选的值
type Gender = '男' | '女';
let gender:Gender = "男";
gender = "女"
type Direction = 'up' | 'down' | 'left' | 'right';
// direction的只能是 up ,down ,left ,right 中的任意一个
// 优点:使用字面量类型更加精确,严谨
function changeDirection(direction:Direction){
console.log(direction)
}
changeDirection('left');
any类型的作用是逃避TS的类型检查
显示any: 当变量的类型指定为any的时候,不会有任何错误,也不会有代码提示,TS会忽略类型检查
隐式any:声明变量不给类型或初始值,函数参数不给类型或初始值
any的使用越多,程序可能出现的漏洞越多,因此【不推荐】使用any类型,尽量避免使用
// 显式any
let obj:any = {age:18}
obj.bar = 100
// 不会报错 将来可能出现错误
obj = 23;
// 隐式any
let aa ;
const fn5 = (n4) =>{}
有时候你会比ts更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型
// alink的类型 HTMlElement,该类型只包含a元素特有的属性或方法
HTMLElement 使用这个类型 太宽泛 没包含a元素特有的属性或方法 href
const alink = document.getElementById('link')
<a id="link"></a>
我们很明确alink 获取到的就是一个a元素,通过类型断言,给它指定一个更具体的类型
const alink = document.getElementById('link') as HTMLAnchorElement
const img= document.getElementById('img') as HTMLImageElement
在ts中,泛型是一种创建可复用代码组件的工具,这种组件不只能被一种类型使用,而是能被多种类型复用。类似于参数;
泛型是一种用于 增强类型(types)、接口(interfaces)、函数类型等能力的非常可靠的手段
泛型: 定义类型别名后 加上 <类型参数> 就是泛型语法,使用时传入具体的类型即可
是一个变量,可以随意命名,建议遵循大驼峰命名法
和类型别名配合,在类型别名后加上泛型语法,然后类型别名内就可以使用这个类型参数
泛型可以提高类型的复用性和灵活性
type User = {
name:string;
age:number
}
type Goods = {
id:number;
goodsName:string;
}
type Data = {
msg:string;
code:number;
data:T
}
// 使用类型
type UserData = Data
type GoodsData = Data
interface IdFn {
id:()=>T;
ids:()=>T[]
}
const idObj:IdFn = {
id(){return 1},
ids(){ return [1,2,3]}
}
// 内置的泛型接口
const arr7 = ["a","b"]
// Ts有类型推断能力 其实可以看作 const arr7:Array = [1,2,3]
const arr8:Array = [1,2,3]
// 通过Ctrl + 鼠标左键 去查看内置的泛型接口
arr7.push("7")
arr7.forEach(item=>(console.log(item)))
// 泛型函数
function getId(id:T):T{
return id
}
let id1 = getId(1)
// TS会进行类型推断 参数的类型作为泛型的类型
let id2 =getId("2")
let id3 = getId({name:"zs"})