TypeScript学习笔记

数据类型

定义类型时,必须(最好)指定变量类型

  1. 布尔类型 boolean

  2. 数字类型 number

  3. 字符串类型 string

  4. 数组类型 array

    let arr1: Array<string> = ["a", "b", "c"];
    let arr2: string[] = ["a", "b", "c"];
    let arr3: any[] = ["a", "b", 4];
    
  5. 元组类型 tuple

  • 也是数组的一种

    // 必须为每一个数组元素单独指定类型(顺序不能调换;必须与元素数量一致)
    let arr3: [number, string] = [123, "a"];
    
  1. 枚举类型 enum

    enum Flag {
        success = 0,
        failed = 1
    }
    // 打印得到对应的赋值;如果没有赋值的话就是对应下标
    const fl: Flag = Flag.success;
    const fa: Flag = Flag.failed;
    // fixme 如果自定义中间某个元素的 value = val ,再打印的话,该元素前后的元素 value 是什么???
    // 后面的 value = val + 1;
    // 前面的没有指定 value 的仍然按照默认的赋值
    
  2. 任意类型 any

       // 不晓得什么类型的就可以这么用
       let oBox: any = document.getElementById("box");
       oBox.style.color = 'red';
    
  3. null 和 undefined

  • 定义的变量未赋值时就是 undefined

     // 一个元素可能是多种类型
     let num2: number | undefined;
     console.log(num2);
     // null 空类型;一个变量为空类型时就只能赋值 null
     let nul:null;
     nul = null;
    
  1. void 类型
  • 表示没有任何类型

  • 一般用于定义方法的时候表示没有返回值

     // 方法不能返回多种类型
     function run(): void {
         console.log("void一般表示方法没有返回类型")
    }
    
  1. never 类型
  • 是其他类型(包括 null 和 undefined)的子类型,代表从不会出现的值

  • 意味着声明 never 的变量只能被 never 类型所赋值

    let nev: never;
    // nev = 3;
    nev = (() => {
        throw new Error("错误");
    })();
    // 最后的这个括号什么意思???
    

函数定义

  1. 函数声明法

    function func(): number {
        return 1;
    }
    
  2. 匿名函数

    const func0 = function (): number {
        return 123;
    };
    func0();
    
  3. 方法和可选参数

    // 使用问号 ? 表示参数可选
    // 可选参数必须是最后一个
    function func2(name: string, age?: number): void {
        if (age) {
            console.log(`${name}`);
        } else {
            console.log(`${name} --- ${age}`);
        }
    }
    func2("yangcx");
    
  4. 方法默认参数

    // 通过等号赋予了默认值,就不能使用 ? 表示参数可选
    // 其实通过 = 也表示了参数可选,不过有了默认值
    function func3(name: string, age: number = 20): void {
        console.log(`${name} --- ${age}`);
    }
    func3("张三",30);
    
  5. 剩余参数(三点运算符接收)

    // 调用的时候优先满足前面明确的参数赋值,剩下的全部赋给...arg
    function func4(a: number, ...result: number[]): number {
        let sum = 0;
        result.forEach(((value) => {
            sum += value;
        }));
        return sum;
    }
    
  6. 函数重载(类似于Java的实现)

    // 多种方法定义,不能拥有具体的方法实现
    // 存在一个同名的方法负责具体实现(所有参数及返回都必须定义为 any )
    function getUserInfo(name: string): string;
    function getUserInfo(age: number, address?: string): string;
    function getUserInfo(str: any): any {
        if (typeof str === 'string') {
            return "My name is " + str;
        } else if (typeof str === 'number') {
            return "My age is " + str;
        }
    }
    
    console.log(getUserInfo("李晨"));
    console.log(getUserInfo(42));
    
  7. 箭头函数(里面的 this 指向上下文)

    // 这只是一个非常简单的示范,具体还需要去看 ES6 语法
    setInterval(() => {
        alert("箭头函数");
    }, 1000);
    

  1. ES5类定义

    function Person() {
        // 属性
        this.name = "张三";
        this.age = 20;
        // 实例方法
        this.run = function () {
            alert(this.name + " 在运动...");
        }
    }
    
    let person = new Person();
    person.run();
    
    // 原型链上面的属性会被多个实例共享;构造函数的不会
    Person.prototype.sex = "男";
    Person.prototype.work = function () {
        alert("张三在工作");
    };
    console.log(person.sex);
    
  2. ES5类中的静态方法

    Person.getInfo = function () {
        console.log("静态方法");
    };
    Person.getInfo();
    
  3. ES5中的继承(原型链+对象冒充的组合继承模式)

    //对象冒充实现
    function Web() {
        Person.call(this);
    }
    
    let web = new Web();
    //对象冒充可以继承构造函数里面的属性和方法
    web.run();
    //但是无法继承原型链上面的属性和方法
    // web.work();
    
    //原型链实现
    Web.prototype = new Person();
    let w = new Web();
    // 可以同时继承构造函数和原型链的属性和方法
    // 如果父类为有参构造,子类实例化时无法给父类传参
    w.run();
    w.work();
    
    // 综合实现写法一
    function Man(name,age){
        Person.call(this,name,age);//对象冒充
    }
    Woman.prototype = new Person();//原型链
    // 综合实现写法二
    function Woman(name,age){
        Person.call(this,name,age);
    }
    Woman.prototype = Person.prototype;
    
  4. TypeScript中定义类(new 对象的时候都无法使用对应类型进行接收)

    class Person {
        name: string;
        age: number;
        //构造函数
        constructor(name: string, age: number) {
            this.name = name;
            this.age = age;
        };
        //方法定义
        run(): void {
            alert(this.name);
        }
        getName(): string {
            return this.name;
        }
        setName(name: string): void {
            this.name = name;
        }
    }
    
    let person = new Person("张三", 25);
    person.run();
    
  5. TypeScript实现类继承(new 对象的时候都无法使用对应类型进行接收)

     // 通过 extends 关键字实现继承   
    class Man extends Person {
    	// 必须 super 对应的构造函数
        constructor(name: string, age: number) {
            super(name, age);
        }
    }
    const man = new Man("王五", 25);
    man.run();
    // 与 Java 继承类似,子类可以调用(override)父类方法或扩展自己的方法
    
  6. TypeScript中的修饰符(与 Java 类似;属性不加修饰符,默认就是 public 的)

    • public 共有的;当前类及子类、类外面都可以访问
    • protected 保护类型;当前类、子类可以访问,类外面无法访问
    • private 私有类型;仅当前类可以访问
    class Person {
        // protected private
        public name: string;
        constructor(name: string) {
            this.name = name;
        }
        consoleName(): void {
            console.log(this.name);
        }
    }
    
    let p = new Person("张三");
    // 跟 Java 类似,直接访问对应属性失败,通过对应的方法可以访问
    console.log(p.name);
    
  7. TypeScript 静态方法 静态属性

    class Person {
    	// static 修饰即可
        static sex: string = "男";
        static staticMethod(): void {
            alert('静态方法就没得this获取属性能力了,除非获取静态属性:' + Person.sex);
        }
    }
    // 直接类名调用就行
    Person.staticMethod();
    
  8. TypeScript 的多态(属于继承;父类定义方法,可提供默认实现;由子类提供具体实现;各子类可以有不同的实现)

  9. TypeScript 抽象方法 抽象类

    • abstract 关键字

    • 抽象类提供其他类继承的基类,不能直接被实例化

    • 抽象方法不包含具体实现并且必须在派生类中实现

    • 存在抽象方法的类必须是抽象类(跟Java类似)

    abstract class Animal {
        //提供方法定义即可
        abstract eat(): any;
    }
    
    class Dog extends Animal {
        name: string;
        constructor(name: string) {
            super();
            this.name = name;
        }
    
        // 必须实现抽象方法
        eat(): any {
            console.log("阿福");
        }
        // 可以拥有自己的方法
        run(): void {
            console.log(`${this.name} is running...`)
        }
    }
    
    let dog = new Dog("dog");
    dog.eat();
    dog.run();
    
  10. TypeScript 接口

    • 属性类接口 对json的约束
    • 函数类型接口
    • 可索引接口
    • 类类型接口
    • 接口扩展
    // 属性类接口
    // 不使用类型约束
    function printLabel(labelInfo: { label: string }): void {
        console.log(labelInfo.label);
    }
    // 相当于使用匿名类定义入参
    printLabel({label: "not a interface"});
    
    // 属性类接口
    interface Label {
        name: string;
        // 参数可选
        width?: number;
        height?: number
        // 设置候选值
        dataType?: 'json' | 'jsonp'
    }
    function drawLabel(label: Label): void {
        console.log(label.height + " <===> " + label.width);
    }
    
    // 直接将属性定义放在调用方法上不能添加任何自定义属性
    drawLabel({name: "label"});
    // 这么写虽然可以添加自定义属性,但是破坏了TS提供的类型校验
    let otherLaber = {
        name:"label",
    width:10,    
        brightness:"dark"
    };
    drawLabel(otherLaber);
    // (推荐)还是把对应的类型限制加上最好
    let otherLaber2:Label = {
        name:"label",
        width:10
    };
    drawLabel(otherLaber);
    
    // 函数类型接口
    interface Encrypt {
        (key: string, value: string): string;
    }
    
    let md5: Encrypt = function (key: string, value): string {
        // 模拟操作
        return key + value;
    };
    md5("yangcx", "20200330");
    
    // 可索引接口:数组、对象的约束(没什么卵用)
    // 数组
    // interface UserArray {
    //     // 定义的格式  索引:值
    //     [index: number]: string;
    // }
    
    // let arr: UserArray = ['aaa', 'bbb'];
    // console.log(arr[0]);
    // // 对象
    // interface UserObj {
    //     [index: string]: string;
    // }
    // let user: UserObj = {name: "yangcx"};
    
    // 类类型接口:对类型的约束(与抽象类类似)
    interface Animal {
        // 同时包含属性与方法定义
        name: string;
        eat(food: string): void;
    }
    // 采用实现 implements
    class Dog implements Animal {
        name: string;
    	// 需要进行构造
        constructor(name: string) {
            this.name = name;
        }
    	// 实现方法
        eat(food: string): void {
            console.log("A " + this.name + " is eating " + food);
        }
        // 可以拥有自定义方法
    	wc() {
            console.log(this.name + " is wcing...");
        }
    }
    let dog = new Dog("dog");
    dog.eat("bone");
    dog.wc();
    
    // 接口扩展:接口可以继承接口
    // 语法上跟 Java 非常类似
    interface Animal {
        eat(food?: string): void;
    }
    
    interface Person extends Animal {
        work(): void;
    }
    
    class Programmer {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        coding(language: string) {
            console.log(this.name + " is coding " + language);
        }
    }
    
    class Web extends Programmer implements Person {
        eat(food?: string): void {
            console.log(this.name + " eat " + food);
        }
        work(): void {
            console.log(this.name + " is working...");
        }
    }
    
    let web = new Web("小明");
    web.work();
    web.coding("TypeScript");
    
  11. TypeScript 泛型

    // 泛型函数
    function getData<T>(value: T): any {
        return value;
    }
    console.log(getData("yangcx"));
    
    // 泛型类
    class MinClass<T> {
        public list: T[] = [];
        add(value: T): void {
            this.list.push(value);
        }
        min(): T {
            let minNum = this.list[0];
            for (let i = 0; i < this.list.length; i++) {
                if (minNum > this.list[i]) {
                    minNum = this.list[i];
                }
            }
            return minNum;
        }
    }
    let minCls = new MinClass<number>();
    
    // 泛型接口定义一
    interface ConfigFn {
        <T>(value: T): T;
    }
    
    let getData: ConfigFn = function <T>(value: T): T {
        return value;
    };
    getData<string>("yangcx");
    // 泛型接口定义二
    // (也可以像 函数类型接口 这么用,但是可能每次都要写完整的函数定义)
    interface ConfigFn<T> {
        (value: T): T;
    }
    
    function getData<T>(value: T) {
        return value;
    }
    
    let myGetData: ConfigFn<number> = getData;
    console.log(myGetData(1));
    
    // 将类作为参数类型校验(就是 泛型类)
    class DbUtil<T> {
        add(t: T): boolean {
            console.log("add: " + t);
            return true;
        }
        update(t: T): boolean {
            console.log("update: " + t);
            return true;
        }
    }
    
  12. TypeScript模块

    • 内部模块(命名空间;主要用于组织代码,避免命名冲突)
    // 命名空间也支持 export
    export namespace A {
        interface Animal {
            eat(food: string): void;
        }
    
        export class Dog implements Animal {
            eat(food: string): void {
                console.log(food);
            }
        }
    }
    namespace B {
        interface Animal {
            eat(food: string): void;
        }
    
        export class Dog implements Animal {
            eat(food: string): void {
                console.log(food);
            }
        }
    }
    
    let aD = new A.Dog();
    aD.eat("bone");
    
    • 外部模块(侧重于代码复用,一个模块可能会有多个命名空间)
    let dbUrl = "jdbc:mysql://127.0.0.1:3306";
    function getData(): any[] {
        console.log("get data from db");
        return [
            {
                title: "11111"
            }, {
                title: "11111"
            }
        ];
    }
    // 可以单独 export 每一个方法或变量;也可以使用 export 进行统一处理
    export {dbUrl, getData}
    
    // 引入
    // as 起别名
    import {getData as get,dbUrl} from './modules/db';
    
    // 默认 export
    // 当一个组件只需要 export 出一个方法或变量时
    // 一个组件中只能存在一个 export default
    export default getData;
    import getData from './modules/db';
    
  13. 装饰器(是一种特殊的类型声明,能够被附加到类声明、方法、属性或参数上,可以修改类的行为)

    // 1、类装饰器:普通装饰器(无法传参)
    function logClass(params: any) {
        // params 参数就是对应的类(HttpClient)
        console.log(params);
        // 可以进行扩展
        params.prototype.apiUrl = "xxxxx";
        params.prototype.run = function () {
            console.log("run...");
        }
    }
    
    @logClass
    class HttpClient {
        constructor() {}
        getData(): any[] {
            return [];
        }
    }
    
    // 可以获取到扩展的属性
    let httpClient: any = new HttpClient();
    console.log(httpClient.apiUrl);
    
    // 2、类装饰器:装饰器工厂(可传参)
    // 2.1 普通扩展
    function logClass(params: string) {
        return function (target: any) {
            // target 是被扩展的类(HttpClient)
            console.log(target);
            // params 是传递过来的参数("hello")
            console.log(params);
            // 可以进行扩展
            target.prototype.apiUrl = "https://www.baidu.com"
        }
    }
    
    @logClass("hello")
    class HttpClient {
        constructor() {}
        getData(): any[] {
            return [];
        }
    }
    let httpClient: any = new HttpClient();
    console.log(httpClient.apiUrl);
    
    // 2.2 重载对应的构造函数及方法等
    function logClass(target: any) {
        console.log(target);
        // 重载对应的构造函数及方法等
        return class extends target {
            apiUrl: any = "修改后的apiUrl";
            getData(): void {
                this.apiUrl = this.apiUrl + "====";
                console.log(this.apiUrl);
            }
        }
    }
    
    @logClass
    class HttpClient {
        apiUrl: string | undefined;
        constructor() {
            this.apiUrl = "构造函数初始化的apiURL";
        }
        getData(): void {
            console.log(this.apiUrl);
        }
    }
    let httpClient = new HttpClient();
    httpClient.getData();
    
    // 3、属性装饰器
    function classDecorator(params: any) {
        console.log("这是类装饰器的传参:" + params);
        return function (target: any) {
            console.log("target 是被扩展的类:" + target);
        }
    }
    
    function fieldDecorator(params: any) {
        console.log("这是属性装饰器的传参:" + params);
        return function (target: any, attr: any) {
            console.log("这是被装饰的类:" + target);
            console.log("这是被装饰的属性:" + attr);
            // 改一下属性值 TODO 改不掉在构造函数中给的值
            target[attr] = params;
        }
    }
    
    @classDecorator("class")
    class HttpClient {
        @fieldDecorator("field")
        url: string | undefined;
        constructor() {
            // this.url = "构造函数初始化的url";
        }
        getData(): void {
            console.log(this.url);
        }
    }
    
    let httpClient = new HttpClient();
    httpClient.getData();
    
    // 4、方法装饰器
    // 被应用到方法的属性描述符上,用来监视、修改或替换方法定义
    // 接收三个入参:
    // 	对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
    // 	方法的名称
    // 	方法的属性描述符
    
    // 扩展属性及方法
    function methodDecorator(params: any) {
        console.log(params);
        return function (target: any, methodName: string, methodDesc: any) {
            console.log(target);
            console.log(methodName);
            console.log(methodDesc);
            // 扩展属性及方法(相当于操作 prototype)
            target.apiUrl = "xxxx";
            target.run = function () {
                console.log("run...");
            }
        }
    }
    
    class HttpClient {
        url: string | undefined;
        constructor() {}
        @methodDecorator("method")
        getData() {
            console.log(this.url);
        }
    }
    let httpClient: any = new HttpClient();
    console.log(httpClient.apiUrl);
    httpClient.run();
    
    // 修改方法
    function methodDecorator(params: any) {
        console.log(params);
        return function (target: any, methodName: string, methodDesc: any) {
            // 方法本尊
            console.log(methodDesc.value);
            // 修改方法
            let _method = methodDesc.value;
            methodDesc.value = function (...args: any[]) {
                args = args.map((value) => {
                    return String(value);
                });
                console.log(args);
                // 在当前方法中传入参数 args 并调用 _method
                _method.apply(this, args);
            }
        }
    }
    
    class HttpClient {
        @methodDecorator("method")
        getData(...args: any[]) {
            // 可以获取到装饰器修改后的参数
            console.log("getData()===>" + args);
            console.log("getData()方法执行了");
        }
    }
    
    let httpClient: any = new HttpClient();
    httpClient.getData(123, 'xyz');
    
    // 方法参数装饰器
    // 用的很少,可以通过类装饰器实现
    

    装饰器的执行顺序:

    • 属性装饰器 > 方法装饰器 > 方法参数装饰器 > 类装饰器
    • 如果存在多个同样的装饰器,会先执行后面的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值