typescript修炼指南(二)

大纲

本章主要讲解一些ts的常规用法,涉及以下内容:

  • interface: 接口
  • class : 类
  • function: 函数
  • T : 泛型

之前因本人业务繁忙(太菜了 被拉去改bug了┭┮﹏┭┮), 所以拖更了,后边会陆续补上, 还在踩坑的小伙伴,希望本文能给你们一些帮助 QAQ


接口

基本使用

定义: 用来集中约束数据类型,用关键词interface来定义一个接口

  interface People {
        num:number,
        country: string,
    }

使用接口:

 // 这样就会报错: 因为约定的时候没有name属性
 const getPeople = (people: People) => people.name 
  • 定义可选属性
interface User {
        name: string,
        age: number,
        sex?: string  // ? 表示可选的
    }
  • 定义只读属性
  interface User {
        name: string,
        age: number,
        readonly weight: string, // readonly表示只读
  }
  • 定义函数属性
interface User {
        name: string,
        age: number,
        get: (sex: string)  => string  // 定义参数类型和返回值类型
 }
 
 // 或者直接使用函数接口
interface Func {
    (sex: string) : string  // 注意这里的符号
}

interface User {
    name: string,
    age: number,
    get: Func,  // 使用接口
}
注意点

有时候我们会遇到这样的情况,当调用函数的时候,传入的参数类型有可能是可选类型,举个例子

  • 定义接口
interface User1 {
        name?: string, 
}
  • 定义函数
 const getUser = (user: User1): { result: string} => {
        return {result: user.name }
 }

这时候会报类型错误, 因为返回值也可能是个void类型, 那如何避免?返回的时候也是可选即可

 const getUser = (user: User1): { result?: string} => {
        return {result: user.name }
 }

另外, 当我们调用的时候传入的是额外的属性比如传入age属性, 则需要as断言

  const username = getUser({age: 20} as User1)

或者,我们可以在接口定义的时候传入一个自定义属性约束

 interface User1 {
        name?: string, 
        [propName: string]: any,// 属性名字符串类型, 这种条件下值可以是任意类型了
  }

通过上边约束, 我们就可以实现这样的一个数据类型约束,键key是变化的, key自增变化

const UserP = {
    name: 'lili',
    age: 20,
    userClass: {
        1: 'class1',
        2: 'class2',
       // .....
    }
}
  • 定义约束
 interface mark {
        [name: number]: string 
}
    
interface User2 {
    name: string, 
    age: number,
    userClass: mark
}
接口继承

直接贴代码,比较简单, 也可以多继承的

interface inter1 {
    name: string
}

interface inter2 {
    (age: number) : number
}

interface inter3 {
    get: (name: string) => string
}

interface interAll extends inter1 {
    add: (age: number) => number
}
// 多继承
interface interAll extends inter1, inter2, inter3 {
    add: (age: number) => number
}

类class

抽象类

抽象类中只用于定义,定义的抽象方法,不会实现具体的方法,且不能实例化,只能作为基类,关键词:abstract

abstract class Test {
    add(): void { console.log('add') }
    // 抽象方法不需要实现具体的方法
    abstract remove(): string 
}

// 直接实例化会导致错误
// const test = new Test()

继承抽象类

class Test1 extends Test {
    // 这里如果不实现remove方法就会报错, 因为是抽象方法
    remove() {
        return 'remove'
    }
}
ts中的类关键词
  • public: 公共修饰词 默认都是public 外部可以访问到的
  • protected: 外部无法访问 内部和子类都可以访问
  • private: 私有修饰符 只有内部可以访问
// class中的 关键词
class Test2 {
    // 公共修饰词 默认都是public 外部可以访问到的
    public add() {
        console.log('add')
    }

    //  外部无法访问 内部和子类都可以访问
    protected remove() {
        console.log('remove')
    }

    // 私有修饰符 只有内部可以访问
    private result() {
        console.log('result')
        this.remove() // 可以访问
    } 
}

class Test3 extends Test2 {
    change() {
        this.add() 
        this.remove()
        // 报错  子类无法访问
        //this.result()
    }
}

const test2 = new Test2()
test2.add()
//test2.remove() // 报错
//test2.result() // 报错
作为初始化接口
class Test4 {
    public name: string = 'lili'
    public age: number = 20
    public get(): string { return name }
}

const test4 = new Test4()
console.log(test4.get())
// test.name = 1 // 报类型错误  因为name是string类型

函数

  • 可选参数
const f1 = (a: string = 'f1', b? : number): void => console.log(a,b?b:'')
  • 剩余参数 ...rest
 const f2 = (a: string, ...rest: string[]): void => { }
  • 函数的重载
// 调用批次
function reloadFunc (name: string): { code: number }
function reloadFunc (name: string, age: number): { code: number } 
// 函数实现
function reloadFunc (name: string, age?: number, sex?: string): { code: number } {
    if(name) {
        return { code: 0 }
    }else if(age) {
        return { code: 1 }
    }else {
        return { code: 2 }
    }
}

reloadFunc('lili')
reloadFunc('lili', 20)
//  reloadFunc('lili', 30, '男')  这一行会报一个错误: 期望是2个参数

泛型

基本使用

泛型最大的作用在于灵活,对于代码复用有很大的用处,说白了,类型由调用者决定,从而实现的一种约束
定义: (T代表一种数据类型)

function testT(name: T): T {
    return name
}

// 调用, 传入的是string类型 返回的约束也是该类型
testT('lili') 

同时支持多个类型的传入:

function testT1(name: T, age: F): [T, F] {
    return [name, age]
}

如果传入的是数组类型,需要返回数组的某个属性,比如length属性

 function testT2(arr: Array): number {
    return arr.length  // 如果没指明数组会报不存在length属性错误 加上Array即可
}
在接口中的应用
interface testT3 {
    name: T
}

// 使用它
const test_t: testT3 = { name: 0 }
泛型类
class TestT4 {
    private name: T[] = [] 

    public test(age: T): T {
        return age
    }
}

调用就可以这样

const test_t1 = new TestT4()
test_t1.test(10)
泛型继承

也叫做泛型的约束,约束泛型只能在某个类型范围内,使用关键词extends

// extends 继承某个类型
class TestT5 {
    private name: T[] = [] 

    public test(age: T): T {
        return age
    }
}
const test_t2 = new TestT5() // 这里就必须是这两种类型了
泛型对象索引

比如我们传入一个对象类型,这种情况下编译器是懵逼的 不知道obj有没有key(默认是{})属性且还不知道key的类型

function testT6(obj: T, key: number) {
     return obj[key]       
}

改造一下,让它继承对象的类型,在用属性继承(keyof)这个类型,可能难理解, 直接看代码

 function testT6(obj: T, key: U) {
    return obj[key]
 }
泛型继承接口

泛型并不支持多继承,也就是说T extends A,B,C 这样是行不通的, 但是我们可以先用接口实现多继承,然后在继承这个接口, 也就是说 interface A extends B,C,D 然后 T extends A

interface testFunc extends A,B,C{
    name: string,
    age: number,
}

function testT7(obj: T) {
    return obj
}
泛型构造函数约束

如果传入的参数是一个构造函数比如:

 function testT8(func: T) {
     return new func() // 这样会报错, 因为不知道是构造类型
}

改造一下: ( new( ) )

function testT8(func: {new(): T}): T {
    return new func() 
}

如果对大家有帮助记得点赞个~ , 如有错误请指正, 我们一起解决,一起进步 ~

你可能感兴趣的:(typescript修炼指南(二))