TypeScript基础和一点点进阶

201 阅读4分钟

基础

基础类型:number string boolean array object

  1. enum 枚举 不显式赋值的话 0 1 2 顺延
enmu Status {
    NOT_START,
    STARTED
}

const status = Status.NOT_START;
  1. type inerface
type UserInfo = {
    name: string;
    height: number;
}

interface UserInfo {
    name: string;
    height: string;
}
  1. 联合类型 (|)

  2. 交叉类型 &

  3. typeof

// js
typeof 'a' // string

// ts
function toArray (x: number): Array<number> {
    return [x];
}

type Func = typeof toArray // (x: number) => number[]
  1. keyof
// 可以获取一个对象中所有的key

interface Person {
    name: string;
    age: number;
}

type KPerson = keyof Person;
const str: KPerson = 'name';
const str: KPerson = 'age';
  1. in

用来遍历枚举类型

type keys = 'a' | 'b' | 'c';

type Obj = {
    [key in keys]: any
}
  1. extends 继承
   interface ILength {
       length: number;
   }
   
   function login <T extends ILength>(arg: T): T {
       console.log(arr.length);
       return arg;
   }
  1. paritial

    patitial 将某个类型的属性全部变为可选项目

    interface Page {
        title: string;
        content: string;
    }
    
    type OptionalPage = patitial<page>;
    
    
  2. required 将某个类型里的属性全部变成必选项目

  3. Readonly

interface Page {
    title: string;
}

const ReadonlyPage = Readonly<Page>

  1. Record Record<K extends keyof any, T> 将K 中所有属性的值转化为T类型

  2. Exclude

    Exclude<T, U> 将某个类型中属于另一个的类型移除掉

    type TO = Exclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
    
  3. Extract

    Extract<T, U> 取 T 和 U 的交集

进阶

  1. ts的优势

    • TS 是 JS 的超集,给js提供了可选的静态类型和基于面向对象,拓展了JS的语法。
    • 类型约束
    • 面向对象的编程语言,包含类和接口的概念
    • 在开发时候就能给出编译错误
    • 强类型语言,明确的知道各种数据的类型,代码可读性很强
    • ts中有很多很方便的特性, 可选链
       if (obj && obj.aa && obj.aa.bb) 
       
       // if (obj?.aa?.bb)
     
    
  2. type 和 interface

    用interface来描述数据结构,用type来描述类型

    • 都支持描述一个对象或者函数
    interface User {
        name: string;
        age: number;
    }
    
    type User = {
         name: string;
         age: number;
    }
    
    • interface 与 type 都可以extends 可以互相extens

    • type 可以声明基本类型别名,联合类型,元组等类型

    type Name = string;
    interface A {}
    interface B {}
    type pet = A | B;
    type pet = A & B;
    
  3. 如果基于一个已有类型,扩展出一个大部分内容相似,但是部分区别的类型

Pick Omit

interface Test {
    name: string;
    sex: number;
    height: string;
}

type Sex = Pick<Test, 'sex'>

const a:Sex = { sex: 1 };

type WithoutSex = Omit<Test, 'sex'>

const b: WithoutSex = { name: '1111', height: '100px' }

通用泛型

  1. 什么是泛型,泛型的具体使用

泛型是指在定义函数或者类的时候,不预先执行具体的类型,而是使用的时候再去指定类型的一种特征

interface Test<T = any> {
    userId: T
}

type TestA = Test<string>
// { userId: string }
  1. 用装饰器实现一个计算函数运行时间的逻辑

export function measure (target, name, descriptor) {
    const oldValue = descriptor.value; // 原有的函数
    descriptor.value = async function () {
        const startTime = Date.now();
        const res = await oldValue.apply(this, arguments);
        console.log(Date.now() - startTime)
    }
    return descriptor;
} 

// 使用

@measure
created () {
    console.log('呜呜呜');
}
  1. 缓存的装饰器
const cecheMap = new Map();
export function EnableCache (target, name, descriptor) {
    const val = descriptor.value;
    descriptor.value = async function (...args) {
        const key = name + JSON.stringify(args);
        if (!cacheMap.get(key)) {
            const cacheValue = Promise.resolve(val.apply(this, args)).catch(_ => {
                cacheMap.set(key, null)
            });
            
            cacheMap.set(key, cacheValue);
        }
        return cacheMap.get(key)
    }
    return descriptor;
}
  1. 实现路由跳转,通过ts约束参数的routerHelper
export type BaseRouterType = Dictionary<string> //  { string: string }

export interface IndexParams extends BaseRouteType {
    name: string
}

export interface ParamMap {
    [Router.Index]: IndexParams
}

export class RouterHelper {
    public replace<T extends RouterPath>(routePath: T, params: ParmMap[T]) {
        Router.replace({
            path: routePath,
            query: params
        })
    }
    
    public push<T extends RouterPath>(routePath: T, params: ParmMap[T]) {
        Router.replace({
            path: routePath,
            query: params
        })
    }
}
  1. 实现一个基于ts和事件模式的countdown 基础类
import { EventEmitter } from 'eventemitter3';

export interface RemainTimeData {
    /** 天数 */
    days: number;
    /**
     * 小时数
     */
    hours: number;
    /**
     * 分钟数
     */
    minutes: number;
    /**
     * 秒数
     */
    seconds: number;
    /**
     * 毫秒数
     */
    count: number;
}

export type CountdownCallback = (remainTimeData: RemainTimeData, remainTime: number) => void;

// 倒计时状态
enum CountdownStatus {
    running,
    paused,
    stoped,
}

/**
 * 倒计时事件
 */
export enum CountdownEventName {
    START = 'start',
    STOP = 'stop',
    RUNNING = 'running',
}

interface CountdownEventMap {
    [CountdownEventName.START]: [];
    [CountdownEventName.STOP]: [];
    [CountdownEventName.RUNNING]: [RemainTimeData, number];
}

export function fillZero(num: number) {
    return `0${num}`.slice(-2);
}

export class Countdown extends EventEmitter<CountdownEventMap> {
    private static COUNT_IN_MILLISECOND: number = 1 * 100;
    private static SECOND_IN_MILLISECOND: number = 10 * Countdown.COUNT_IN_MILLISECOND;
    private static MINUTE_IN_MILLISECOND: number = 60 * Countdown.SECOND_IN_MILLISECOND;
    private static HOUR_IN_MILLISECOND: number = 60 * Countdown.MINUTE_IN_MILLISECOND;
    private static DAY_IN_MILLISECOND: number = 24 * Countdown.HOUR_IN_MILLISECOND;

    private endTime: number;
    private remainTime: number = 0;
    private status: CountdownStatus = CountdownStatus.stoped;
    private step: number;

    constructor(endTime: number, step: number = 1e3) {
        super();

        this.endTime = endTime;
        this.step = step;
    
        // 初始化countdown实例的时候, 直接开始倒计时
        this.start();
    }

    /** 开始倒计时 */
    public start() {
        // 发布事件:开始倒计时
        this.emit(CountdownEventName.START);

        // 更新状态为 倒计时进行中
        this.status = CountdownStatus.running;
        this.countdown();
    }

    /** 结束倒计时 */
    public stop() {
        // 发布事件:结束倒计时
        this.emit(CountdownEventName.STOP);

        // 更新状态为 倒计时结束
        this.status = CountdownStatus.stoped;
    }

    private countdown() {
        if (this.status !== CountdownStatus.running) {
            return;
        }

        // 保证获取到的remainTime >= 0
        this.remainTime = Math.max(this.endTime - Date.now(), 0);

        // 发布事件 倒计时进行中, 并且传递时间数据
        this.emit(CountdownEventName.RUNNING, this.parseRemainTime(this.remainTime), this.remainTime);

        if (this.remainTime > 0) {
            // 递归countdown
            setTimeout(() => this.countdown(), this.step);
        } else {
            this.stop();
        }
    }

    private parseRemainTime(remainTime: number): RemainTimeData {
        let time = remainTime;

        const days = Math.floor(time / Countdown.DAY_IN_MILLISECOND);
        time = time % Countdown.DAY_IN_MILLISECOND;

        const hours = Math.floor(time / Countdown.HOUR_IN_MILLISECOND);
        time = time % Countdown.HOUR_IN_MILLISECOND;

        const minutes = Math.floor(time / Countdown.MINUTE_IN_MILLISECOND);
        time = time % Countdown.MINUTE_IN_MILLISECOND;

        const seconds = Math.floor(time / Countdown.SECOND_IN_MILLISECOND);
        time = time % Countdown.SECOND_IN_MILLISECOND;

        const count = Math.floor(time / Countdown.COUNT_IN_MILLISECOND);

        return {
            days,
            hours,
            minutes,
            seconds,
            count,
        };
    }
}