TS基础入门

138 阅读6分钟

“携手创作,共同成长!这是我参与「掘金日新计划 · 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. 方法可使用箭头函数
  2. 使用类型别名方便复用,提高代码复用性
  3. 属性和方法设置可选

🔔小练习:

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自动类型推断

  1. 声明变量并提供初始值
  2. 函数的返回值

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 }

✨经验:
  1. 第一原则:尽量避免使用 any 类型,any 使用得越多,程序漏洞越多
  2. 如果使用第三方库不知道是什么类型,可以先用 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')