TypeScript(二)

289 阅读4分钟

1、class

blog.csdn.net/qq119556631…

Ⅰ. 类型约束 implements 继承 extends

构造函数constructor,默认方法或者参数要调用或者接收,在此初始化

class约束关键字 implements

子类调用父类的方法,在类型约束前extends父类;继承父类的子类需要在constructor调用super

Ⅱ. class的修饰符 readonly private protected public

a、readonly 属性只读,不可修改

b、private 只能在类内部调用方法,子类也无法调用父类方法

c、protected 代表定义的变量私有的,只能在内部和继承的子类中访问,不能在外部访问

d、public 默认都为public 外部可以访问

Ⅲ. super

调用父类方法时,须在子类构造函数调用super()

super() 相当于 父类的prototype.constructor.call

可以通过super直接调用父类方法,如:super.render()

Ⅳ. 静态方法

用static定义类或者属性,只能通过类名访问,无法通过this获取

如 Dom.author / Dom.version()

静态方法里this只能获取静态的属性/方法

interface Options {
    el: string | HTMLElement
}

interface VueCls {
    options: Options,
    init(): void
}

interface VNode {
    // 标签、文本、子节点
    tag: string,
    text: string | null,
    children: VNode[]
}

// 实现一个虚拟DOM的方法,创建标签方法/标签填充文本/渲染
class Dom {
    static author: string;
    constructor(name: string) {

    }
    static version() {
        this.author = 'avido';
        return `${this.author} 1.0.0.0`
    }

    private createElement(el: string) {
        return document.createElement(el);
    } 

    private setText(el: HTMLElement, text: string | null) {
        el.textContent = text;
    }

    protected render(data:VNode) {
        let root = this.createElement(data.tag);
        if(data.children && Array.isArray(data.children)) {
            data.children.forEach(item => {
                let child = this.createElement(item.tag);
                this.setText(child,item.text);
                root.appendChild(child)
            })
        } else {
            this.setText(root,data.text)
        }

        return root;
    }

    public recursionNode() {
        // TODO
        // 当前只做了子节点递归,应该包括子节点下的其他节点渲染
    }
}

let dom = new Dom('123');
dom.recursionNode();
Dom.author;
Dom.version();

// Vue类约束类型为VueCls
// 参数通过constructor接收(即初始化),其他方法才能获取该参数
// constructor函数里关于参数、方法、父类方法初始化非常重要!!!
class Vue extends Dom implements VueCls {
    options: Options;
    constructor(options: Options) {
        super('name');
        this.options = options;
        this.init();
    }
    init(): void {
        console.log(this.options)
        let data:VNode = {
            tag: 'div',
            text: 'father',
            children: [
                {
                    tag: 'div',
                    text: 'son1',
                    children: [
                        {
                            tag: 'p',
                            text: 'grandson',
                            children: []
                        }
                    ]
                },
                {
                    tag: 'div',
                    text: 'son2',
                    children: []
                }
            ]
        }

        // 创建根节点,将生成的根节点添加
        let app = typeof this.options.el == 'string' ? document.querySelector(this.options.el) : this.options.el;
        app?.appendChild(this.render(data));
    }
}

new Vue({
    el: '#app'
})

// 总结简单版虚拟dom的实现逻辑
// a、子类声明数据,父类提供创建元素方法,子类调用父类方法
// b、通过多个interface约束对象类型;子类通过extends继承父类
// c、constructor 初始化参数和方法+父类方法

Ⅴ. get set

class Ref {
    _value: any;
    constructor(value: any) {
        this._value = value;
    }

    get value() {
        return this._value + '_1008611';
    }

    set value(newVal) {
        this._value = newVal + '_Avido'
    }
}

// 从打印时能看出声明get和set时,_value和value是不一样的
const ref = new Ref('hey');
console.log(ref.value, ref._value)
ref.value = 'Hello'
console.log('newVal',ref.value,ref._value)

2、抽象类(基类)

abstract 所定义的类即抽象类

abstract 定义的方法,只能描述不能实现

抽象类无法被实例化

abstract class Vue_ab {
    name: string
    constructor(name: string) {
        this.name = name;
    }
    getName(): string {
        return this.name;
    }
    // abstract init() {} // 报错,abstract标记的方法无法实现
    abstract init(name: string):void
}

// const vue_ab =  new Vue_ab(); // 报错,无法实例化

// 用法:派生类继承抽象类
// 派生类需要实现抽象类描述的方法,如上的init
// 继承抽象类的派生类可以被实例化
class  Vue_derive extends Vue_ab {
    constructor() {
        super('111');
    }
    init(name: string): void {

    }
    setName(name: string) {
        this.name = name;
    }

}

const ab_derive = new Vue_derive();
ab_derive.init('init');
console.log(ab_derive.getName())
ab_derive.setName('Hey You Ok?')
console.log(ab_derive.getName())

3、元组类型

是数组的一种

元组中的元素类型可以是不同的,且数量固定,即我们可以获取它的length

如果方法返回多个值,可以作为元组返回,不需要创建类

const arr_tuple = [1,false]; 
// arr_tuple[0] = '222'; // 报错,该元组被识别为number和boolean的联合类型
arr_tuple[0] = 666;
arr_tuple.push(111)

// 元组声明类型
const arr_tuple2: [string,number] = ['you',20];
arr_tuple2[0] = 'oo';

const arr_tuple3: readonly [x: boolean, y?:number] = [true];
// arr_tuple3[1] = 123;  // 报错,readonly只读

let excel: [string,string,number][] = [
    ['Bepo','bear',25],
    ['Leo','man',32]
]
const arr_tuple4: readonly [x: boolean, y:number] = [true,33];
type first_tuple = typeof arr_tuple4[1] // number
type length_tuple = typeof arr_tuple4['length'] // 2

4、枚举类型

TS 通过关键字 enum 定义枚举类型

// Ⅰ. 数字枚举 
// 在js中
let obj = {
    red: 0,
    yellow: 1,
    blue: 2
}

enum Color {
    // 值不声明,默认从0开始
    red,
    yellow,
    blue
}
console.log(Color.red,Color.yellow,Color.blue);

enum Color2 {
    // 递增
    red = 1,
    yellow,
    blue
}
console.log(Color2.red, Color2.yellow, Color2.blue);

// Ⅱ. 字符串枚举
enum Color3 {
    red = 'red',
    yellow = 'yellow',
    blue = 'blue'
}
console.log(Color3.red, Color3.yellow, Color3.blue);

// Ⅲ. 异构枚举(字符串+数字)
enum Color4 {
    is,
    no = 'no',
    // are, // 报错,无法递增
    yes = 1,
    are
}

// Ⅳ. 接口枚举
enum Type_ENUM {
    red = 0,
    yellow
}
interface Type_Val {
    success: Type_ENUM.red,
    fail: Type_ENUM.yellow
}

let type_val: Type_Val  = {
    // success: 1 // 报错,red值为0
    success: 0,
    fail: Type_ENUM.yellow
}
console.log(type_val,'type_val')


// Ⅴ. const枚举
// const 会将ts 编译成常量,否则编译成对象
const enum Type_ENUM2 {
    success,
    fail
}
let code:number = 0;
if(code === Type_ENUM2.success) {
    console.log(Type_ENUM2.success)
}

// Ⅵ. 反向映射
// 通过value获取其key值
// 只支持数字类型!!!
enum Type_ENUM3 {
    success = 200,
    serverError = 500
}
let success:number = Type_ENUM3.success;
let key = Type_ENUM3[success]
console.log(`value---${success}`, `key---${key}`)

查看编译后的js文件,可以看到支持反向映射的原理,是通过value-key形式声明数组。

5、类型推论 类型别名

Ⅰ. 类型推论

声明变量,dan没有定义类型

ts自带类型推论 通过声明的变量及值能自动推断该变量的类型

let type_val2 = [1,2,3];
// type_val2 = ''; // 报错,type_val2 类型为number[]

Ⅱ. 类型别名(type)

type s = string | number[];
let type_str:s = '123';
let type_str2:s = [3,3,3];

// extends 在type中是包含的意思
type type_num = 3 extends number ? 1 : 0;
// let ttt: type_num = 0; // 报错。type为1
let ttt: type_num = 1;

// type 和 interface的区别
// a、interface可以继承 type通过&交叉类型合并
// b、interface重名会合并
// c、type可以定义联合类型、使用一些操作符

6、never 类型

ts使用never类型来表示不应该存在的状态

type Type_never = string & number; // 此时为never类型

function neverFun():never {
    throw new Error('error')
}

type Type_talent = 'sing' | 'jump' | 'rap' | 'basketball';

// 应用场景
// 当新增值 'basketball',default会报错,因新增string,且无法赋值给error
// 这种情况我们可以通过报错识别到少了对'basketball'的case语句
function getTalent(value: Type_talent) {
    switch(value) {
        case 'sing':
            break;
        case 'jump':
            break;
        case 'rap':
            break;
        default: 
            // 用于场景兜底逻辑
            const error:never = value;  // 报错
            console.log('error-value',error);
            break;
    }

    return 
}

7、Symbol 类型

Ⅰ. 定义

支持string number undefined 三种类型

创建各自的内存地址,是唯一的,不会相等

let sy1 = Symbol(1);
let sy2 = Symbol(1);

console.log(sy1,sy2)
console.log(sy1 == sy2);  // false

Ⅱ. for

如何让两个symbol值返回true

for会在全局查找key,有则拿来用,无则创建

console.log(Symbol.for('abc') === Symbol.for('abc'))

Ⅲ. 应用场景

用作对象属性的键

let sy_obj = {
    name: '111',
    // name: '222', // ts报错,js覆盖处理
    [sy1]: '111',
    [sy2]: '222'
}
console.log(sy_obj)

Ⅳ. 读取对象里的symbol值

// for in 不支持
for(let key in sy_obj) {
    console.log(key, 'for in')
}

// Object.keys 不支持
console.log(Object.keys(sy_obj),'Object.keys')

// JSON.stringify 不支持
console.log(JSON.stringify(sy_obj), 'JSON.stringify')

// Object.getOwnPropertyNames 不支持
console.log(Object.getOwnPropertyNames(sy_obj),'Object.getOwnPropertyNames');

// Object.getOwnPropertySymbols 只能获取对象中的symbol类型
console.log(Object.getOwnPropertySymbols(sy_obj),'Object.getOwnPropertySymbols');

// ES6语法 Reflect.ownKeys 获取对象所有属性
console.log(Reflect.ownKeys(sy_obj), 'Reflect.ownKeys')

8、迭代器 生成器

Ⅰ. 生成器 定义

function* gen() {
    yield Promise.resolve('avido') // 同步异步
    yield '1'
    yield '2'
    yield '3'
}

const empGen = gen();
// empGen.next();

// 按照顺序调用,和同步异步无关
// done为true,表示后面无生成器可迭代
console.log(empGen.next())
console.log(empGen.next())
console.log(empGen.next())
console.log(empGen.next())
console.log(empGen.next())

Ⅱ. Set Map

// Set 支持数字和字符串去重
let set1:Set<number> = new Set([1,1,2,2,3,3]) // 天然去重
console.log(set1,'set1')

// map定义key-value
// 实现将引用类型作为key
let map1:Map<any,string> = new Map();
const map_arr = [0,1]
map1.set(map_arr,'avido')
console.log(map1)
console.log(map1.get(map_arr))

// 伪数组
function args() {
    console.log(arguments)
}
// let list = document.querySelectorAll('div')  // 伪数组

Ⅲ. 迭代器

如何支持所有数据类型(如Set、Map、伪数组等)的遍历

他们自身已定义迭代器

对象不能使用for of,因为对象身上没有Symbol.iterator

// ① 迭代器的语法糖  for of
// 对象不能使用for of,因为对象身上没有Symbol.iterator
for(let i of map1) {
    console.log(i,'for of')
}
// for(let i of {name: ''})

// ② for of 的实现原理
// value[Symbol.iterator]().next().value
const each = (value:any) => {
    let It:any = value[Symbol.iterator]()
    let next:any = { done: false }
    while(!next.done) {
        next = It.next();
        if(!next.done) {
            console.log(next.value)
        }
    }
}

each(set1)
each(map1)

// ③ 数组的解构原理也是通过Symbol.iterator实现
let [e,f,g] = [3,6,9];
console.log(e,f,g,'[e,f,g]')
let arr_sy = [0,1]
let arr_sy_copy = [...arr_sy]
console.log(arr_sy_copy,'arr_sy_copy')

// ④ 如何使对象支持for of
let obj_iterator = {
    max: 4,
    current: 0,
    [Symbol.iterator]() {
        return {
            max: this.max,
            current: this.current,
            next() {
                if(this.max === this.current) {
                    return {
                        value: undefined,
                        done: true
                    } 
                } else {
                    return {
                        value: this.current++,
                        done: false
                    }
                }
            }
        }
    }
}

for(let i of obj_iterator) {
    console.log(i,'obj_iterator')
}
for(let i of [...obj_iterator]) {
    console.log(i,'[...obj_iterator]')
}
console.log([...obj_iterator])
for(let i of {...obj_iterator}) {
    console.log(i,'{...obj_iterator}')
}
// 对象如何实现解构?
// 创建新变量、枚举属性、属性赋值(Object.keys,Object.getOwnPropertySymbol)