大纲
本章主要讲解一些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()
}
如果对大家有帮助记得点赞个~ , 如有错误请指正, 我们一起解决,一起进步 ~