“携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,[点击查看活动详情]
TS基础
初学者技巧
书写技巧
- 先书写 js 部分,再添加 ts 类型注解
解读技巧
- 先删除掉函数的 ts 类型,解读功能,再去理解类型
ts类型注解
需要添加导入、导出或空的
export {}语句来使当前文件成为模块
:number就是类型注解,为变量提供类型约束
原始类型
string number boolean undefined null
❗原始类型首字母是小写
✨项目一般不会主动声明undefined和null,一般在出现错误的时候回看到
数组类型
作用:约束数组每一项的类型
✨推荐语法:类型[]
let arr:number[] = [1,2,3]
❌类型 string 的参数不能赋给类型 number 的参数 arr.push('1')
❌类型 number 的参数不能赋给类型 string 的参数
联合类型
语法:一根竖线
let arr:(string | number)[] 或者 let guess:string | number[]
- 解读:数组类型的每一项为 字符串类型或数值类型
❌不能将类型boolean分配给类型(string | number)[]
❌❗不能将类型string[]分配给类型string | number[]
类型别名
作用:用于存储 TS 类型,方便
类型复用
语法: type 类型别名 = 具体类型
命名建议:使用大驼峰命名法,类型别名首字母大写
type MyType = (string | number)[]
let arr1:MyType
let arr2:MyType
函数类型
基本用法
定义
- 函数参数的类型
- 函数返回值的类型
写法
-
在函数基础上
分别指定参数和返回值类型const res = (num1:number,num2:number):number => { return num1 + num2 } -
使用类型别名
同时指定参数和返回值type AddType = (num1:number,num2:number) => number const add1:AddType = (num1,num2) =>{ return num1 + num2 }
函数类型-void类型
用于标注函数没有返回值
const sayHi = ():void =>{
console.log('hello')
}
❗ 返回值类型不为 void 的函数,必须有返回值
const sayHi2 = ():undefined =>{
console.log('hello')
return
}
函数类型-可选参数
语法:参数后面+?
❗ 必选参数不能位于可选参数后
const fn = (n?:number):void => {
...
}
fn()
fn(10)
const mySlice(start?:number,end?:number):void => {
console.log(`开始索引为${start},结束索引为${end}`)
}
mySlice()
mySlice(1)
mySlice(1, 2)
对象类型
描述对象的结构,规定对象属性的方法和类型
基本用法
❌ 空对象 let obj1: {} = { name: 'zs' } let obj2: object = { age: 18 }
❌存在问题:不指定对象属性和具体类型,无法访问对象的属性
✅ 给对象的属性指定类型
let obj3: { name:string } = { name:'zs' }
✅给对象的多个属性指定类型,一行书写用 ;隔开,如果换行可以不写;
let obj4:{
name:string
age:number
}
拓展用法
-
方法可使用箭头函数
-
使用类型别名方便复用,提高代码复用性
-
属性和方法设置可选
🔔小练习:
1. 声明一个既有属性又有方法的对象类型
type ObjType = {
name:string
age:number
sayHi():void
sayNo:() => void
}
let obj5: ObjType = {
name:'zs',
age:19,
sayHi(){},
sayNo(){}
}
2. 为 axios({ url, method }) 添加 ts 类型注解
PS:如果是 get 请求 method 可以省略
const axiosType = {
url:string
method?:string
}
const axios = (config:axiosType) => {
console.log(config)
}
3. 创建一个学生对象,该对象中具有以下属性和方法:
-
属性:必选属性:姓名、性别、成绩,可选属性:身高
-
方法:学习、打游戏(可选)
const StuType = {
name:string
gender:string
score:number
height?:number
study():void
playGame?():void
}
const stu1:StuType = {
name: '悟空',
gender: '男',
score: 100,
height: 150,
study() {
console.log('打妖怪')
},
playGame() {
console.log('playGame~')
},
}
测试必选属性和方法:
stu1.name.trim()
stu1.score.toFixed(2)
stu1.study()
❗❗ 注意:可选属性和方法需要先判断再使用
if(stu1.height){
stu1.height.toFixed(2)
}
if (stu1.playGame) {
stu1.playGame()
}
对象语法补充-可选链操作符
经验:
可选属性或方法,可配合 ?. 可选链操作符 安全使用。
安全调用写法1:判断
if(stu1.playGame){
stu1.playGame()
}
安全调用写法2:短路运算
stu1.playGame && stu1.playGame()
✅安全调用写法3:可选链操作符,最简洁
stu1.playGame?.()
接口类型
用来定义对象的结构,type 和 interface 都可以定义对象的结构 ---- 按团队的习惯来即可
基本用法
interface IsStudent{
name:string
age?:number
sayHi():voids
}
const stu1:IsStudent = {
...
}
通过 type(类型别名)定义对象的结构
type TsStudent = {
name:string
age?:number
sayHi():void
}
扩展---接口继承
interface c{
x:number
y:number
}
// 先继承 Point2D 的所有属性和方法,在花括号内拓展添加自己的属性或方法
interface Point3D extends Piont2D{
z:number
}
扩展---类型别名和交叉类型
type Point3D = Point2D & { z:number }
type 和 interface
共同点:
都可以定义对象类型,在大多数情况下,可以根据个人(团队)喜好进行选择
区别:
type 不能出现重名
interface 重名会自动合并
TS自动类型推断
-
声明变量并提供初始值
-
函数的返回值
let name = 'tony'
❌name = 123 根据初始值,自动推导的类型为 string
TS 字面量类型
基础语法:
TS 中允许把字面量直接当做类型使用
let name:'tony' = 'tony'
应用场景:
✨字面量类型可匹配联合类型使用,实现代码提示和类型校验
let method:'GET'|'POST'|'DELETE'|'PUT'
🔔练习实战:升级 axios 的 method 属性
type Config = {
url:string
// method?:string ❌范围太大了,没有代码提示,单词写错了不知道
method?:'GET'|'POST'|'DELETE'|'PUT'
}
// 为 axios 的参数添加类型注解
const axios = (config:Config) => {
console.log(config)
}
any类型
显式any:
逃避 TS 的类型检查,相当于让代码变回 JS,不检查类型
let obj:any
// ❗风险:以上的代码虽然 书写时 没有报错提示,但是代码 运行时 是可能出现错误的
obj = { name: 'zs', age: 18 }
obj.trim()
隐式any:
声明变量(函数参数),但没有设置类型或初始值
const add = (n1,n2)=>{ return n1+n2 }
✨经验:
- 第一原则:尽量避免使用 any 类型,any 使用得越多,程序漏洞越多
- 如果使用第三方库不知道是什么类型,可以先用 any 逃避 TS 的检查,让程序先跑起来
泛型(类型变量)
作用:提高代码的复用性
语法:先声明,再使用,T 表示类型变量
声明类型变量:<T> 使用类型变量:T
泛型别名
后端返回值类型,通过泛型提升可复用性
<T> 声明泛型
type ResponseType<T> = {
msg:string
code:number
data:T // T 使用泛型,使用前需声明
}
type User = {
name:string
age:number
}
应用
const userRes:ResponseType<User> = {
msg: 'ok',
code: 200,
data: {
name: 'zs',
age: 18,
},
}
项目中更安全的访问
userRes.data.name
泛型接口
interface IdFn<T>{
id:T
getId():T
getIds():T[]
}
const idFn:IdFn<number> = {
id:123,
getId(){
return 123
},
getIds(){
return [1,2]
}
}
泛型函数
function getId<T>(id:T){
return id
}
const res1 = getId<number>(1)
const res2 = getId<string>('wendy')
// ✨调用的时候,可以根据实参推导出参数的类型,可以省略不写
const res3 = getId(123)
泛型约束 extends
约束 T 的类型范围是 'GET' | 'POST'
function fn1<T extends 'GET' | 'POST'>(params:T)T{
return params
}
约束 T 的类型必须有 length 属性
function fn2<T extends { length:number }>(params:T):T{
console.log(param.length)
return param
}
封装抽离写法
interface Len{
length:number
}
function fn3<T extends Len }>(params:T):T{
console.log(param.length)
return param
}
fn2([1, 2, 3])
fn3('123')