TypeScript 入门:高级类型

勾勾的前端世界

共 5366字,需浏览 11分钟

 · 2021-07-11

类型断言

const nums = [2,66,88]// TS 的类型推断无法确定res 的结果const res = nums.find(i => i >0)
// 而此时,res 就不能当作纯数字使用// const t = res * res // res 报错
// 我们根据代码逻辑,知道res 一定是number,就可以直接断言const n1 = res as number// 使用res断言后的结果 n1const n2 = n1 * n1console.log(n2)


断言的语法规则就是变量xx  as 类型xx或者<类型xx> 变量xx,意思就是告诉 TS ,我的代码一定是某种类型的,放心使用。<类型xx> 变量 xx 的方式在 React 中会与 JSX 语法规则冲突,因此一般更建议使用 as 语法规则

 

接口 Interfaces


基本使用

functionprint(post:Objpost){  // 传入的对象中,必须有 title 和 content  console.log(post.title)  console.log(post.content)}// 但是,并不能保证调用者一定传入符合条件的对象print({name:'xiling'})使用接口进行内容约束:// 定义接口interface Objpost{  // 属性名:类型 //使用逗号和分号或者不写都可以  title:string  content:number}
// 形参使用接口,标注传入的内容,符合接口的定义functionprint(post:Objpost){ // 传入的对象中,必须有 title 和 content console.log(post.title) console.log(post.content)}print({name:'xiling'}) // 报错print({title:'lisi',content:66})

 


可选与只读属性

// 定义接口interface Objpost {  // 属性名:类型 //使用逗号和分号或者不写都可以  title: string  content: number
subtitle?: string // 可选成员属性 readonly summary: string // 只读属性,一旦赋值则不可修改}
// 形参使用接口,标注传入的内容,符合接口的定义functionprint(post: Objpost) { // 传入的对象中,必须有 title 和 content console.log(post.title) console.log(post.content)}
let obj:Objpost = { title:'lisi',content:66,summary:'xiling' }obj.summary='liuneng'// 修改只读属性,报错print(obj)


动态成员

interfaceCache {  // [定义动态成员:类型]:值类型  [props:string]:string}
const obj: Cache = {}// 动态添加对象成员obj.title='javaScript'obj.content='html'
console.log(obj)


类的使用


基本使用

class Person{  // 在类中初始化属性定义  name:string='lisi'// 定义初始值  age:number
constructor(name:string,age:number){ this.name=name this.age=age this.sex='男'// 没有初始化的成员会报错 }
SayHi(msg:string):void{ console.log(`Hello ${this.name},${msg}`) }}


访问修饰符

class Person{  // 类中的修饰符有三种 public  private  protected  // public 公有属性,任何地方都可以访问  // protected 受保护属性,只有自己和继承的子类中能访问  // private 私有属性,只在类内部访问  public name:string='lisi'  private age:number  protected gender:boolean
constructor(name:string,age:number){ this.name=name this.age=age this.gender=true }
SayHi(msg:string):void{ console.log(`Hello ${this.name},${msg}`) console.log(this.gender) }}
class Student extends Person{ sya(){ this.gender }}
let stu =newStudent('lisi',66)stu.namestu.age// 私有属性,外部访问报错stu.gender// 受保护属性,外部访问报错


类的只读属性

class Person{  // 设置成员为只读属性,一旦赋值,不可修改  public readonly name:string='lisi'
constructor(name:string,age:number){ this.name=name }
SayHi(msg:string):void{ this.name='liuneng'// 修改报错 }}


类与接口

// 人和动物都有运动和吃东西的行为// 都有这样的行为,但确实不一样的;// 这样的情况下,我们就可以使用接口描述不同的行为约束
class Person { eat(food: string) { console.log(`使用筷子:${food}`) }
run(distance: number) { console.log(`双脚:${distance}`) }}
class Animal { eat(food: string) { console.log(`撕咬的吃:${food}`)) }
run(distance: number) { console.log(`四蹄${distance}`) }}


人和动物都有运动和吃东西的行为,都有这样的行为,但确实不一样的。这样的情况下,我们就可以使用接口描述不同的行为约束。

 

// 接口只做行为的约束,不做具体方法的实现interface eatAndrun {  eat(food: string):void  run(distance: number):void}
// 使用 implements 关键字进行约束class Person implements eatAndrun { eat(food: string) { console.log(`使用筷子:${food}`) } // 如果缺少约束的成员,则会报错 // run(distance: number) { // console.log(`双脚:${distance}`) // }}


但是在实际的开发中,接口约束会更加的细致,就类似摩托车也能跑,但并不是人或动物,细致的约束会更加灵活。


// 对接口进行细致化的拆分interface eat {  eat(food: string):void}
interface run { run(distance: number):void}
// 使用多个接口,需要逗号,隔开class Person implements eat,run { eat(food: string) { console.log(`使用筷子:${food}`) } // 如果缺少约束的成员,则会报错 run(distance: number) { console.log(`双脚:${distance}`) }}


抽象类与抽象方法


抽象类

与接口类似,但是接口只能进行规范约束不能具体实现,而抽象类可以具体实现。抽象类的定义很简单,只需要在类声明的前面添加 abstract 就可以了。

abstract class Animal {  eat(food:string):void{    console.log(`撕咬的吃:${food}`)  }}


类一旦被抽象,就不能被实例化,只能使用子类继承使用。

// newAnimal() // 报错--无法创建抽象类的实例class Dog extends Animal{
}


抽象方法
abstract class Animal {  eat(food:string):void{    console.log(`撕咬的吃:${food}`)  }  // 定义抽象方法run , 需要在继承的子类中实现(必须实现)  abstract run(distance:number):void}
class Dog extends Animal{ // 抽象方法必须在子类中实现 run(distance: number):void { console.log(distance) }}


泛型

在定义函数、接口或者类的时候,没有指定具体的类型,等到使用时才会具体指定的一种特征。

// 函数定义时,参数及返回值并不能确定类型// 或者,函数需要在运行时固定类型// 函数名后面使用 <占位符> ,在不确定类型的地方,使用 :占位符function createArray<T>(length: number, value: T): T[] {  const arr =Array<T>(length).fill(value)  return arr}
// 函数调用时,使用函数名<泛型的具体类型> (实参1,实参2)createArray<string>(3,'xl')


类型声明

我们在进行项目开发时,肯定会用到一些第三方模块,但是这些第三方模块不一定是 TS 的,那就无法使用强类型的友好开发体验。

 

以 lodash 为例,使用 npm install lodash 安装后,通过 import 语法引入。

// 无法找到模块“lodash”的声明文件。import {camelCase} from'lodash'
// camelCase 将字符串转为驼峰格式const res =camelCase('hello xiling') // 没有类型提示console.log(res)


引入后就出现了错误提示:'无法找到模块“lodash”的声明文件。


同时提示中也告诉我们安装 npm install @types/lodash -D 模块来解决这个问题,已开发依赖的方式安装即可,@types/lodash 其实就是声明文件,成功安装之后,操作就消失了。


而有的模块直接拥有声明文件,这时就不需要额外安装扩展库了。


但是,有一些相对陈旧的库,在使用时自身没有声明文件,也没有对应的文件库这就需要我们自己在代码中进行处理了。


我们依然以 lodash 为例,npm uninstall @types/lodash 卸载类型声明文件,模拟这种情况,无法找到模块“lodash”的声明文件。


camelCase 也没有类型提示:因为确实没有类型声明文件,所以,我们尝试解决 camelCase 的类型提示,其实只需要使用 declare 关键字进行标注就可以了:

// 无法找到模块“lodash”的声明文件。import {camelCase} from'lodash'
declare functioncamelCase(input:string):string
// camelCase 将字符串转为驼峰格式const res =camelCase('hello xiling') // 没有类型提示console.log(res)


Over。


推荐阅读:

前端自动化测试:TDD 和 BDD 哪个好?

Windows11 抢先体验,带你安装

Hexo 博客搭建教程

Webpack 的运行机制和核心工作原理


更新不易,点个“在看”和“”吧(●'◡'●)!

浏览 75
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报