TypeScript基础知识点集合(三)

142 阅读3分钟

关于对象类型和函数类型之类的,还有一些补充。

函数可是设置可选参数

// 可选参数 ?
function css1(el: HTMLElement, attr: string, val?: any) {

}
let div = document.querySelector('div');
div && css1(div, 'width', '100px');
div && css1(div, 'color');

可以通过联合类型和默认值来设置函数默认参数

// 默认参数
function sort1(items: Array<number>, order = "desc") {

}
sort1([1, 2, 3]); // order不填  默认 desc
// 也可以通过联合类型来限制取值
function sort2(items: Array<number>, order: "desc" | 'asec' = "desc") {

}
sort2([1, 2, 3]); // order不填  默认 desc
sort2([1, 2, 3], "asec");
// sort2([1, 2, 3], "abc"); // error

函数定义剩余参数

如果函数的参数有一部分参数是相同的类型标注,则可以通过interface进行统一标注

// 剩余参数
interface IObj {
    [key: string]: any;
};
function merge(target: IObj, ...others: Array<IObj>) {
    return Object.assign(target, ...others);
}
let newObj = merge({x: 1}, {y: 2}, {z: 3});

利用 类型断言 解决this指向问题

普通函数中的this是谁调用的话就会指向谁,普通函数中的`this`一般为any会报错。
interface T {
    a: number;
    fn: (x: number) => void;
};
// 在第一个参数位显示的标注this 解决this指向问题
let tf_obj1: T = {
    a: 1,
    fn(this: T,x: number) {
        
    }
};

箭头函数中的this固定的,this指向当前函数的作用域环境。

interface T {
    a: number;
    fn: (x: number) => void;
};
let ft_obj2: T = {
    a: 1,
    fn(this: T, x: number) {
        return () => {
            // 不能动态的改变箭头函数中的this
            // fn中的this指向什么,内部的箭头函数中的this就指向什么
        }
    }
};

函数重载

一个函数有时候会传入不同的参数,不同的参数类型输入会有相对应的不同的返回结果,所以就需要用到函数重载

重载函数不需要实体,只需要定义其结构(类似于接口)。

interface PlanObject {
    [key: string]: string | number;
}
function czcss(ele: HTMLElement, attr: PlanObject);
function czcss(ele: HTMLElement, attr: string, val: string | number);
function czcss(ele: HTMLElement, attr: any, val?: any) {
    if(typeof attr === "string" && val) {
        ele.style[attr] = val;
    }
    if(typeof attr === "object") {
        for(let key in attr) {
            ele.style[key] = attr[key];
        }
    }
}
if(div1) {
    czcss(div1, 'width', '100px');
    czcss(div1, {
        height: '100px',
    });
    // czcss(div1, 'opacity'); // error
}

类的定义

class User {
    /**
     * 
     * @param id 
     * @param username 
     * 当我们给构造函数参数设置了访问修饰符:public,ts会做如下两件事情
     * - 给当前类添加同名的成员属性
     * - 在类的实例化的时候,会把传入的参数值赋值给对应的成员属性
     */
     constructor(
        public id: number,
        public username: string,
    ) {
        // 创建类的函数,当类通过new实例化的时候,就会执行该函数
        console.log('this is constructor');
        // this.id = id;
        // this.username = username;
    };
    // 方法
    postArticle(title: string, content: string) {
        console.log(`${this.username}发表了一篇文章${title},内容为${content}`)
    };
}
let user1: User = new User(1, '1'); // use
user1.postArticle('title', 'content');

类的继承

当子类继承父类时,需要通过super调用父类的构造函数,且this必须在super之后使用。

class VIP extends User {
    constructor(
        id: number,
        username: string,
        public score: number,
    ) {
        super(id, username); // 调用父类构造函数
        console.log(this.id); // this必须在super之后使用
        console.log('vip');
    };
}

类中的方法也可以通过重写,重新实现父类的方法,但是需要保持参数的一致。

postArticle(title: string, content: string): void {
    this.score++;
    console.log(`${this.username}发表了一篇文章${title},内容为${content},分数${this.score}`);
};

类中也可以实现方法重载

postArticle(title: string, content: string);
postArticle(title: string, content: string, file: string);
postArticle(title: string, content: string, file?: string): void {
    super.postArticle(title, content);
    if(file) {
        this.postAttachment(file);
    }
 }



postAttachment(file: string) {
    console.log(`${this.username}上传了${file}`)
};
let vip = new VIP(2, '2', 22);
vip.postArticle('222', '234');
vip.postAttachment('1.png');
vip.postArticle('333', '345', '2.png');

类的修饰符

类还具有一些修饰符:public protected private readonly

  • readonly 可以访问 但是一旦确定不能修改
  • protected 可以访问 但是不能外部修改
  • private 外部包括子类都不能访问 也不可以修改

类还具有寄存器set | get,类似于defineObject的getter | setter

set password(password: string) {
     if(password.length >= 6) {
         this._password = password;
     }
}
get password(): string {
     return '****';
}

类的静态成员 static

如果一个成员方法中没有使用或者是依赖this,那么该方法就是静态的。

类的静态成员 是通过 类名.静态成员访问的。

class User {
    // static 必须在 readonly 之前
    static readonly ALLOW_IMG_TYPE_LIST: Array<IAllowFileTypeList> = 
    ['png' , 'gif' , 'jpg' , 'jpeg' , 'webp'];
    constructor(
        public id: number,
    ) {};
    
    static info() {
        console.log(User.ALLOW_IMG_TYPE_LIST);
    }
}
console.log(User.ALLOW_IMG_TYPE_LIST);

抽象类 abstract

子类继承了抽象类,那么该子类就必须实现抽象类中的所有抽象方法,否则该类还得声明为抽象的。

// Component不能实例化
abstract class Component<T1, T2> {

    props: T1;
    state: T2;

    constructor(props: T1) {
        this.props = props;
    };

    // render(): string {
    //     return '';
    // };

    abstract render(): string;
}

// 可以用于规范化类的设计规范
interface IMyComponentProps {
    val: number;
}
interface IMyComponentState {
    x: number;
}

/**
 * 类和接口
 * 接口 使用 implements
 */
// 抽象类编译后还是会产生实体代码,但是接口不会
// 一个子类只能有一个父类,但是一个类可以实现多个接口
// 接口不能有实现,抽象类可以
interface ILog {
    getInfo(): string;
}
// 接口也是可以继承的
interface IStrong extends ILog {
    // 有 getInfo 和 save
    save(data: string): void;
}

class MyComponent extends Component<IMyComponentProps, IMyComponentState> 
implements ILog {

    constructor(props: IMyComponentProps) {
        super(props);
        this.state = {
            x: 1,
        };
    };

    render(): string {
        this.props.val;
        this.state.x;
        return '<myComponent />';
    };

    getInfo(): string {
        return `<mycomponent> props ${this.props} state ${this.state}`;
    }
}

let mycomponent = new MyComponent({val: 1});
mycomponent.render();

function log(target) {
    target.getInfo();
}

log(mycomponent);

类型保护

类型保护,类似于类型断言,根据判断逻辑的结果,缩小类型的范围(精确类型)。

一般使用逻辑条件语块 if else elseif 或者一些关键词 typeof instanceof in is... 来实现。

Tips

in 内部使用for...in对类型进行遍历(in后面的类型必须是string | number | Sumbol)

获取类型的key - keyof

keyof可以获取类型的所有key的集合。

类型兼容 implements

implements可以实现一些类共有方法或者属性的提取。

interface IFly {
    fly(): void;
}

class Person implements IFly {
    name: string;
    age: number;
    study() {}; 
    fly(): void {
        
    };
}
class Cat {
    name: string;
    age: number;
    catchMouse() {};
}

let p = new Person();
let c = new Cat();

function fn(arg: IFly) { // 接口 兼容
    arg.fly();
}
fn( p ); // c没有fly