大纲
本章主要讲解一些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() }