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<T>(name: T): T {
    return name
}

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

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

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

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

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

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

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

调用就可以这样

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

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

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

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

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

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

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

 function testT6<T extends object, U extends keyof T>(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<T extends testFunc>(obj: T) {
    return obj
}
泛型构造函数约束

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

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

改造一下: ( new( ) )

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容