typescript 笔记 最全demo

1,282 阅读10分钟

typescript 笔记

tsc --init 生成 tsconfig.json

typescript 中的数据类型

typescript 中为了使编写代码更规范, 更有利于维护,增加了类型校验

  1. 布尔类型 boolean

         let isDone: boolean = false;
    
  2. 数字类型 number

        let decLiteral: number = 6;
    
  3. 字符串类型 string

        let name: string = "bob";
    
  4. 数组类型 Array 有两种方式可以定义数组。

        // 第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组:
        let list: number[] = [1, 2, 3];
    
        // 第二种方式是使用数组泛型,Array<元素类型>
        let list: Array<number> = [1, 2, 3]
    
  5. 元组类型 tuple 属于数组的一种, 可以给数组每个位置指定类型

    let x: [string, number];
     // Initialize it
     x = ['hello', 10]; // OK
     x = [10, 'hello']; // Error
    
  6. 枚举类型 enum 比如在项目中我们用 status = 0 表示失败 status = 1 表示成功 但是时间久了 我们并不知道 0 1 代表的状态

        enum Status {sucess=1, error=0}
        let result: Status = Status.sucess
        console.log(result)
    
  7. 任意类型 any

        // dom 节点不是 的对象在  ts 中会有警告
        let Obox: any = document.getElementById('box)
        obox.style.color="res"
    
  8. Null 和 Undefined undefined和null两者各自有自己的类型分别叫做undefined和null

        let u: undefined = undefined;
        let n: null = null;
    
        // 一个元素可能是 number 或者 null 或者 undefined
        var num: number | null | undefined
    
  9. void类型 void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是void:

        function warnUser(): void {
            console.log("This is my warning message");
        }
    

    方法返回 指定类型

        function num(): number {
            return 100
        }
    
  10. nerver 联合

typescript 中的函数

  1. 函数声明

        function add(): number {
            return 123
        }
    
        let add = function(): number {
            return 123
        }
    
  2. 方法传参

        function getUser(name: string, age: string) {
            return name + " " + age;
        }
    
  3. 方法可选参数

    JavaScript里,可传可不传。 没传参它的值就是undefined。 在TypeScript里我们可以在参数名旁使用?实现可选参数的功能

        function buildName(firstName: string, lastName?: string) {
            if (lastName)
                return firstName + " " + lastName;
            else
                return firstName;
        }
    
  4. 默认参数 es5 不能设置默认参数, es6 和 ts 中可以设置

        function getUser(name: string, age: string = '20') {
        }
    
  5. 剩余参数 你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在JavaScript里,你可以使用arguments来访问所有传入的参数。

        function sum(...resule: number[]) {
            // 在这里可以循环 resule
        }
        sum(1, 2, 3, 4)
    
        function sum(a, b, ...resule: number[]) {
            // 在这里可以循环 resule
            // 这个时候 a = 1, b = 2 , resule = [3, 4]
        }
        sum(1, 2, 3, 4)
    
  6. 重载 根据传入不同的参数而返回不同类型

         function done(x:string):string;
         function done(x:number):number;
         function done(x:any):any{
             if(typeof x=="string"){
                 return "ts"
             }else if(typeof x=="number"){
                 return 5
             }
         }
    
  7. 箭头函数作用域 和 es6 一样 这里不做解释了。

  1. es5 里边的类, 但是 没有类的概念 通过构造函数

        function Person() {
            this.name = "张三"
            thia.age = 20
        }
        // 实例化调用
        let p = new Person()
        console.log(p.name)
    
  2. 构造函数和原型链里边定义方法

        function Person() {
            this.name = '张三';
            this.age = 20;
            this.run = function () {
                console.log(this.name + '在运动')
            }
        }
        // 原型链上面的属性会被多个实例共享,而构造函数不可以
        Person.prototype.sex = '男'
        Person.prototype.work = function () {
            console.log(this.name + '在工作')
        }
        // 调用原型链上的方法
        p.work()
    
  3. 类里边的静态方法

        function Person() {
            this.name = name;
            this.run = function () {    // 实例方法
                console.log(this.name + '在运动')
            }
        }
        Person.getInfo = function () {
            console.log('我是静态方法')  // 不需要实例化调用
        }
    
        // 调用静态方法
        Person.getInfo()
    
  4. es5 里边的继承 对象冒充

        function Person() {
            this.name = name;
            this.run = function () {
                console.log(this.name + '在运动')
            }
        }
        Person.prototype.work = function () {
            console.log(this.name + '在工作')
        }
    
        // web 类 继承 Person 类 原型链 + 对象冒充的组合继承模式
    
        function Web () {
            Person.call(this) // 对象冒充实现继承
        }
        var web = new Web()
        web.run() // 兑现冒充可以继承构造函数里边的属性和方法
        web.work() // 会报错, 对象冒充可以继承构造函数的属性和方法, 但是没办法继承原型链的属性和方法
    
  5. es5 里面的 原型链继承

        function Person() {
            this.name = name;
            this.run = function () {
                console.log(this.name + '在运动')
            }
        }
        Person.prototype.work = function () {
            console.log(this.name + '在工作')
        }
    
        function Web () {  // 原型链继承
        }
        Web.prototype = new Person()
        var web = new Web()
        web.run() 
        web.work() // 原型链继承 可以继承构造函数的属性和方法, 也可以继承原型链上面的属性和方法
    
    
  6. es5 里面的 原型链继承实例化的时候不能传递参数

        function Person(name, age) {
            this.name = name;
            this.age = age;
            this.run = function () {
                console.log(this.name + '在运动')
            }
        }
        Person.prototype.work = function () {
            console.log(this.name + '在工作')
        }
    
        function Web (name, age) {  // 原型链继承
        }
        Web.prototype = new Person()
        var web = new Web('张三', 20)
        web.run() // 这里会报 undefined 在运动 ,实例化子类的时候没办法给父类进行传参
    
  7. es5 里面的 原型链+对象冒充组合继承

        function Person(name, age) {
            this.name = name;
            this.age = age;
            this.run = function () {
                console.log(this.name + '在运动')
            }
        }
        Person.prototype.work = function () {
            console.log(this.name + '在工作')
        }
    
        function Web (name, age) {
            // 进行传参
            Person.call(this, name, age)
        }
        Web.prototype = new Person()
        var web = new Web('张三', 20)
        web.run()
    
  8. es5 里面的 原型链+对象冒充组合继承 的另一种形式

        function Person(name, age) {
            this.name = name;
            this.age = age;
            this.run = function () {
                console.log(this.name + '在运动')
            }
        }
        Person.prototype.work = function () {
            console.log(this.name + '在工作')
        }
    
        function Web (name, age) {
            // 因为这里可以继承构造函数的属性和方法
            Person.call(this, name, age)
        }
        // 这里可以继承原型链上的属性和方法
        Web.prototype = Person.prototype
        var web = new Web('张三', 20)
        web.run()
    

ts 中定义类

    class Person {
        name: string;   // 属性 前面省略了 public 关键字
        constructor(message: string) {  // 构造函数, 实例化的时候触发的方法
            this.name = message;
        }
        run():void {
            console.log("Hello, " + this.name)
        }
        getName (): string {
            return this.name
        }
        setName (name): void {
            this.name = name
        }
    }

    let p = new Person("world");
    p.setName('李四')

ts 中如何实现继承 extends 、 super

    class Person {
        name: string;   // 属性 前面省略了 public 关键字
        constructor(message: string) {  // 构造函数, 实例化的时候触发的方法
            this.name = message;
        }
        run():string {
            return `${this.name} 在运动`
        }
    }

    class Web extends Person{
        constructor (name: string) {
            super(name) // 初始化父类的构造函数
        }
        // 如果子类和父类的方法一致, 会执行子类的 run 方法
        run():string {
            return `${this.name} 在运动`
        }
    }

    var web = new Web('李四')
    web.run()

ts 中的修饰符 typescript 里面定义属性给我们提供了 三种修饰符

  1. public : 公有,在类里面,子类 类外边 都可以访问
  2. protected 保护类型, 在类里边 子类都可以访问,在类外部没法访问
  3. private 只能在类里面访问

属性不加修饰符 就是公有属性

    class Person {
        name: string;   // 属性 前面省略了 public 关键字
        constructor(message: string) {  // 构造函数, 实例化的时候触发的方法
            this.name = message;
        }
        run():string {
            // 在 内部访问
            return `${this.name} 在运动`
        }
    }

    class Web extends Person{
        constructor (name: string) {
            super(name) // 初始化父类的构造函数
        }
        // 如果子类和父类的方法一致, 会执行子类的 run 方法
        run():string {
            // 在子类 访问
            return `${this.name} 在运动`
        }
    }

    var web = new Web('李四')
    web.run()

    // 在类外部访问公有属性
    var p = new Person('外部访问')
    console.log(p.name)

typeScript 类中的 静态属性、 方法、 多态

  1. 静态方法

        class Person {
            name: string;
            constructor(message: string) {
                this.name = message;
            }
            run():string {
                // 在 内部访问
                return `${this.name} 在运动`
            }
            static sex = '男'
            static work (): string {
                // 这里在调用的时候 this.name 是 undefined, 在静态方法中只能使用静态属性
                return `${this.name}在运动`
                // 使用静态属性
                return `${Person.name}在运动`
            }
        }
        // 调用静态方法
        Person.work()
    
  2. 多态 父类定义一个方法不去实现, 让他继承的子类去实现 每一个子类有不同的表现

        class Animal {
            name: string;
            constructor (name) {
                this.name = name
            }
            // 父类定义一个方法 让子类去实现
            eat () {}
        }
    
        class Dog extends Animal {
            constructor (name) {
                super(name)
            }
            eat (name) {
                return this.name + '吃粮食'
            }
        }
    
        class Cat extends Animal {
            constructor (name) {
                super(name)
            }
            eat (name) {
                return this.name + '吃老鼠'
            }
        }
    
  3. 抽象方法 typescript中的抽象类,他是提供其他类继承的基础,不能直接被实例化 用 abstract 关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现

        // Animal这个类的子类必须包含 eat 方法
        // 抽象类
        abstract class Animal {
            eat () {}
        }
        // 这里直接报错, 抽象类不能被实例化
        var animal = new Animal()
    
        class Dog extends Animal {
            constructor (name) {
                super(name)
            }
            // 抽象类的子类必须要实现 抽象类的抽象方法
            eat (name) {
                return this.name + '吃粮食'
            }
        }
    

typescript 中的接口

面向对象编程中,接口是一种规范的定义,它定义了行为和动作规范 在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批所需要遵守的规范 接口不关心这些类内部状态数据,也不关心这些类里面方法的实现细节它只规定了这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。 typescript中的接口类似java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等

  1. 属性接口 对 json 的约束

    • 对批量方法进行约束
        // 必须传入一个对象, 包含 属性 label 值是 string 类型
        function printLable (labelInfo: {label: string}): void {
            console.log('printLable')
        }
        printLable({label: '张三'})
    
        interface FullName {
            firstName: string; // 这里必须用分号结束
            lastName: string
        }
        function printLable (name: FullName): string {
            return `${name.firstName} -- ${name.lastName}`
        }
        let obj = {
            age:20, // 如果对象直接写在 printLable 括号内 age 会报错
            firstName: '张',
            lastName: '三'
        }
        printLable(obj)
    
    
    • 可选属性
        interface FullName {
            firstName: string;
            lastName?: string   // 可选属性
        }
        function printLable (name: FullName): string {
            return `${name.firstName}`
        }
        let obj = {
            firstName: '张',
    
        }
        printLable(obj)
    
        // 定义接口
        interface Config {
            type: string;
            url: string;
            data?: string;
            dataType: string;
        }
    
  2. 函数类型接口 对方法传入的参数, 和返回值进行约束

        // 加密函数
        interface encrypt {
            (key: string, value: string): string
        }
        var md5: encrypt = function (key: string, value: string): string {
            return key + value
        }
        md5('name', 'zhangsan')
    
  3. 可索引接口 数组 对象的约束 (不常用)

        // 数组的约束
        interface StringArray {
            [index: number]: string;
        }
    
        let myArray: StringArray;
        myArray = ["Bob", "Fred"];
        let myStr: string = myArray[0];
    
        // 对象的约束
        interface StringObject {
            [index: number]: string
        }
    
        let myObject: StringObject = {name: '张三'};
    
  4. 类 类型接口 和 抽象类有点相似

        // 继承的 类 必须有 name 属性 和 eat 方法
        interface Animal {
            name: string;
            eat (str: string): void
        }
    
        class Dog implements Animal{
            name: string;
            consstructor (name: string) {
                this.name = name
            }
            eat () {
                console.log(this.name + '吃饭')
            }
        }
    
  5. 接口扩展 接口继承

        // 继承的 类 必须有 name 属性 和 eat 方法
        interface Animal {
            name: string;
            eat (str: string): void
        }
        // 继承 Animal 的接口
        interface Person extends Animal {
            work() :void
        }
    
        class Programmer {
            consstructor (name: string) {
                this.name = name
            }
            coding (code: string) {
                console.log(this.name + code)
            }
        }
    
        // Web 继承了父类 然后使用 Person 接口
        class Web extends Programmer implements Person {
            // Web 类 必须有 接口Animal 的 name 属性 和 eat 方法 还有 Person 接口的 work 方法
            name: string;
            consstructor (name: string) {
                this.name = name
            }
            eat () {
                console.log(this.name + '吃饭')
            }
            work () {
                console.log(this.name + '写代码')
            }
        }
    

typescript 泛型

解决 类 接口 方法的复用性以及不确定数据的支持

    function getData (value: string) {
        return value
    }
    // getData 现在只能返回 string 类型, 如果有可能返回 number 类型 就需要重新定义一个一样的方法

    function getData<T> (value: T): T {
        return value
    }

    getData<number>(123)    // 参数必须是数字
    getData<string>('123') // 参数必须是字符串

    // 泛型类
    class MinClas<T>{
        public list:T[]=[];
        add(value:T):void{
            this.list.push(value);
        }
        min():T{
            var minNum=this.list[0];
            for(var i=0;i<this.list.length;i++){
                if(minNum>this.list[i]){
                    minNum=this.list[i];
                }
            }
            return minNum;
        }
    }

    var m1=new MinClas<number>();   /*实例化类 并且制定了类的T代表的类型是number*/
    m1.add(11);
    m1.add(3);
    m1.add(2);
    alert(m1.min())

    var m2=new MinClas<string>();   /*实例化类 并且制定了类的T代表的类型是string*/
    m2.add('c');
    m2.add('a');
    m2.add('v');
    alert(m2.min())

    // 函数类型接口
    interface ConfigFn = {
        (value: string, value1: string): string
    }

    var setData: ConfigFn = function (value: string, value1: string): string {
        return value + value1
    }
    // 现在只能传入字符串类型
    setData('name', '张三')

    //修改成泛型接口,写法1
    interface ConfigFn{
        <T>(value:T):T;
    }
    // 执行 functon 为 泛型  value 也为泛型, 返回值也是泛型的接口
    var getData:ConfigFn= function<T>(value:T):T{
        return value;
    }
    console.log(getData<string>("zhangsan"))

    //修改泛型接口, 写法2
    interface ConfigFn<T>{  // 把 泛型标识 <T> 写在上边
        (value:T):T;
    }

    function getData<T>(value:T):T{
        return value;
    }
    // 指定泛型接口 职位 string
    let mySetFunc:getData<string> = getData;
    console.log(mySetFunc("zhangsan"))

定义一个 User 的类这个类的作用就是映射数据库字段 然后定义一个 MysqlDb 的类, 这个类用作操作数据库, 然后把 User 类作为参数传入 MysqlDb 中

    // 数据库表字段的映射
    class User {
        usernam: string | undefined;
        password: string | undefined;
    }

    class MysqlDb {
        // 这样确实能操作成功 但是我们在这里 写死了 User 数据库字段映射, 不能重复使用 add 的方法
        add(user: User): boolean {
            console.log(user);
            return true;
        }
    }

    var u1 = new User();
    u1.usernam = "admin";
    u1.password = "123456"

    var msql = new MysqlDb();
    msql.add(u1);
    // 数据库表字段的映射
    class User {
        usernam: string | undefined;
        password: string | undefined;
    }

    class MysqlDb {
        // 这样确实能操作成功 但是我们在这里 写死了 User 数据库字段映射, 不能重复使用 add 的方法
        add(user: T): boolean {
            console.log(user);
            return true;
        }
    }

    var u1 = new User();
    u1.usernam = "admin";
    u1.password = "123456"
    // 我们在这里 进行 数据库User表 的验证
    var msql = new MysqlDb<User>();
    msql.add(u1);

综合案例

需求: 功能: 定义一个操作数据库的库 支持Mysql MongoDb 要求1: Mysql MongoDb功能一样,都有add update delete get方法 注意: 约束统一的规范、以及代码重用 解决方案: 需要约束规范所以要定义接口,需要代码重用所以用到泛型 1、接口: 在面向对象编程中,接口是一种规范的定义,它定义了行为和动作的规范 2、泛型:通俗理解:泛型就是解决 类 接口 方法的复用性

装饰器

注意  装饰器是一项实验性特性,在未来的版本中可能会发生改变。若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json里启用experimentalDecorators编译器选项:

    {
        "compilerOptions": {
            "target": "ES5",
            "experimentalDecorators": true
        }
    }

类装饰器

普通装饰器(无法传参)

    // params 就是当前的类 HttpClient
    function logClass(params:any) {
        console.log(params) // ƒ HttpClient() {}
        params.prototype.str = "动态添加的属性";
        params.prototype.fn2 = function () {
            console.log('动态添加的方法')
        }
    }

    @logClass
    class HttpClient {
    constructor() {

    }
    fn1() {

    }
    }

    let httpClient:any = new HttpClient();
    console.log(httpClient.str) //动态添加的属性
    httpClient.fn2() //动态添加的方法

装饰器工厂(可传参)

    function logClass(params:string) {
    return function(target:any) {
        console.log(target) // ƒ HttpClient() {}
        console.log(params) //hello

        target.prototype.str = params + '属性';
        target.prototype.fn2 = function () {
        console.log(params + '方法')
        }
    }
    }

    @logClass('动态添加的')
    class HttpClient {
        constructor() {}
        fn1() {}
    }

    let httpClient:any = new HttpClient();
    console.log(httpClient.str) //动态添加的属性
    httpClient.fn2() //动态添加的方法

重载构造函数的例子

    function logClass(target:any) {
    return class extends target {
        apiUrl:any = '我是修改后的url';
        fn1 () {
            console.log(this.apiUrl)
        }
    }
    }

    @logClass
    class HttpClient {
        public apiUrl:string | undefined;
        constructor() {
            this.apiUrl = 'http://www.baidu.com'
        }
        fn1 () {
            console.log(this.apiUrl)
        }
    }

    let http = new HttpClient();
    http.fn1() //我是修改后的url

属性装饰器

    // 属性装饰器
    function logProperty(params:string) {
        return function(target:any, attr:any) {
            console.log(params) //我是属性装饰器
            console.log(target) // {fn1: ƒ, constructor: ƒ}
            console.log(attr) //url

            target[attr] = params
        }
    }

    class HttpClient {
        @logProperty('我是属性装饰器')
        public url:any | undefined;
        constructor() {
        }
        fn1() {
            console.log(this.url) //我是属性装饰器
        }
    }

    let httpClient:any = new HttpClient();
    httpClient.fn1()