• Typescript 基础应用


    什么是 TypeScript

    TypeScript 是微软开发的 JavaScript 的超集,TypeScript兼容JavaScript,可以载入JavaScript代码然后运行。TypeScript与JavaScript相比进步的地方 包括:加入注释,让编译器理解所支持的对象和函数,编译器会移除注释,不会增加开销;增加一个完整的类结构,使之更新是传统的面向对象语言。

    TypeScript 优势

    TypeScript 主要特点包括:

    • TypeScript 是微软推出的开源语言,使用 Apache 授权协议
    • TypeScript 是 JavaScript 的超集
    • TypeScript 增加了可选类型、类和模块
    • TypeScript 可编译成可读的、标准的 JavaScript
    • TypeScript 支持开发大规模 JavaScript 应用
    • TypeScript 设计用于开发大型应用,并保证编译后的 JavaScript 代码兼容性
    • TypeScript 扩展了 JavaScript 的语法,因此已有的 JavaScript 代码可直接与 TypeScript 一起运行无需更改
    • TypeScript 文件扩展名是 ts,而 TypeScript 编译器会编译成 js 文件
    • TypeScript 语法与 JScript .NET 相同
    • TypeScript 易学易于理解

    JavaScript 与 TypeScript 的区别

    • TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
    • TypeScript 是 JavaScript 的类型的超集,它可以编译成纯 JavaScript。编译出来的 JavaScript 可以运行在任何浏览器上。TypeScript 编译工具可以运行在任何服务器和任何系统上。TypeScript 是开源的。
    • TypeScript 增加了代码的可读性和可维护性
      类型系统实际上是最好的文档,大部分的函数看看类型的定义就可以知道如何使用了,可以在编译阶段就发现大部分错误,这总比在运行时候出错好,增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等。
    • TypeScript 非常包容
      TypeScript 是 JavaScript 的超集,.js 文件可以直接重命名为 .ts 即可,即使不显式的定义类型,也能够自动做出类型推论,可以定义从简单到复杂的一切类型,即使 TypeScript 编译报错,也可以生成 JavaScript 文件,兼容第三方库,即使第三方库不是用 TypeScript 写的,也可以编写单独的类型文件供 TypeScript 读取。

    TypeScript 对JavaScript的改进主要是静态类型检查

    1. 静态类型检查可以做到early fail,即你编写的代码即使没有被执行到,一旦你编写代码时发生类型不匹配,语言在编译阶段(解释执行也一样,可以在运行前)即可发现。针对大型应用,测试调试分支覆盖困难,很多代码并不一定能够在所有条件下执行到。而假如你的代码简单到任何改动都可以从UI体现出来,这确实跟大型应用搭不上关系,那么静态类型检查确实没什么作用。
    2. 静态类型对阅读代码是友好的,比如我们举个例子 jQuery API Documentation 这是大家都非常喜欢用的jQuery.ajax,在这份文档中,详尽地解释了类型为object的唯一一个参数settings,它是如此之复杂,如果没有文档,我们只看这个函数声明的话,根本不可能有人把这个用法猜对。针对大型应用,方法众多,调用关系复杂,不可能每个函数都有人编写细致的文档,所以静态类型就是非常重要的提示和约束。而假如你的代码像jQuery这样所有函数基本全是API,根本没什么内部函数,而且逻辑关系看起来显而易见,这确实跟大型应用搭不上关系,那么静态类型对阅读代码确实也没什么帮助。总的来说,现代编程语言设计,很多特性已经有非常成熟的理论支持了,如果我们重视计算机基础,那么一些语言的适用场景就像是拼积木,可以用几句话概括。像是TS对JS这样,只是单一特性变化。

    TypeScript 的缺点

    • 有一定的学习成本,需要理解接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)等前端工程师可能不是很熟悉的东西
    • 短期可能会增加一些开发成本,毕竟要多写一些类型的定义,不过对于一个需要长期维护的项目,TypeScript 能够减少其维护成本
    • 集成到构建流程需要一些工作量
    • 可能和一些库结合的不是很完美

    如何使用

    安装Typescript
    npm install -g typescript
    编译.ts文件-->javescript
    编译 tsc xxx.ts
    实时编译 tsc xxx.ts -w

    语法简介

    类型

    js原始数据类型包括:布尔值、数值、字符串、null、undefined
    在js基础上新加了any,void类型

    在 TypeScirpt 中,可以用 void 表示没有任何返回值的函数
    声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null
    undefined 和 null 是所有类型的子类型

    如果是 any 类型,则允许被赋值为任意类型
    声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值
    变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型
    如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型

    如果是一个普通类型,在赋值过程中改变类型是不被允许的

    对象的类型——接口

    在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implements)
    赋值的时候,变量的形状必须和接口的形状保持一致
    未定义任意属性时,多些、少些属性都是不被允许的
    一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性
    只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

    interface Person {
        readonly id: number;       // 只读属性
        name: string;              // 确定属性
        age?: number;              // 可选属性
        [propName: string]: any;   // 任意属性
    }
    let tom: Person = {
        name: 'Tom',
        gender: 'male'
    };
    

    函数的类型
    一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义较简单:

    function sum(x: number, y: number): number {
        return x + y;
    }
    

    也可以使用接口的方式来定义一个函数需要符合的形状:

    interface SearchFunc {
        (source: string, subString: string): boolean;
    }
    
    let mySearch: SearchFunc;
    mySearch = function(source: string, subString: string) {
        return source.search(subString) !== -1;
    }
    
    // 编译前
    function buildName(firstName: string, lastName?: string) {
        return lastName ? firstName + ' ' + lastName : firstName
    }
    // 编译后
    function buildName(firstName, lastName) {
        return lastName ? firstName + ' ' + lastName : firstName;
    }
    

    输入多余的(或者少于要求的)参数,是不被允许的
    可选参数后面不允许再出现必须参数
    TypeScript 会将添加了默认值的参数识别为可选参数

    剩余参数

    // 编译前
    function push(array, ...items) {
        items.forEach(function(item) {
            array.push(item);
        });
    }
    // 编译后
    function push(array) {
        var items = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            items[_i - 1] = arguments[_i];
        }
        items.forEach(function (item) {
            array.push(item);
        });
    }
    

    元组

    数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象
    元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
    let xcatliu: [string, number] = ['Xcat Liu', 25];
    当赋值给越界的元素时,它类型会被限制为元组中每个类型的联合类型:

    let xcatliu: [string, number];
    xcatliu = ['Xcat Liu', 25, 'http://xcatliu.com/'];
    

    枚举

    枚举(Enum)类型用于取值被限定在一定范围内的场景

    枚举使用 enum 关键字来定义
    枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射
    一个枚举类型可以包含零个或多个枚举成员。 枚举成员具有一个数字值,它可以是 常数或是计算得出的值
    enum Color {Red, Green, Blue = "blue".length};

    enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
    // 编译后
    var Days;
    (function (Days) {
        Days[Days["Sun"] = 0] = "Sun";
        Days[Days["Mon"] = 1] = "Mon";
        Days[Days["Tue"] = 2] = "Tue";
        Days[Days["Wed"] = 3] = "Wed";
        Days[Days["Thu"] = 4] = "Thu";
        Days[Days["Fri"] = 5] = "Fri";
        Days[Days["Sat"] = 6] = "Sat";
    })(Days || (Days = {}));
    // Days --> { '0': 'Sun', '1': 'Mon', '2': 'Tue', '3': 'Wed', '4': 'Thu', '5': 'Fri', '6': 'Sat', Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 }
    

    给枚举项手动赋值: enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};
    如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 是不会察觉到这一点的

    当满足以下条件时,枚举成员被当作是常数:

    • 不具有初始化函数并且之前的枚举成员是常数。在这种情况下,当前枚举成员的值为上一个枚举成员的值加 1。但第一个枚举元素是个例外。如果它没有初始化方法,那么它的初始值为 0
    • 枚举成员使用常数枚举表达式初始化。常数枚举表达式是 TypeScript 表达式的子集,它可以在编译阶段求值

    当一个表达式满足下面条件之一时,它就是一个常数枚举表达式:

    • 数字字面量
    • 引用之前定义的常数枚举成员(可以是在不同的枚举类型中定义的)如果这个成员是在同一个枚举类型中定义的,可以使用非限定名来引用
    • 带括号的常数枚举表达式
    • +, -, ~ 一元运算符应用于常数枚举表达式
    • +, -, *, /, %, <<, >>, >>>, &, |, ^ 二元运算符,常数枚举表达式做为其一个操作对象。若常数枚举表达式求值后为NaN或Infinity,则会在编译阶段报错

    所有其它情况的枚举成员被当作是需要计算得出的值

    泛型

    泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性

    function swap<T, U>(tuple: [T, U]): [U, T] {
      return [tuple[1], tuple[0]];
    }
    

    在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法

    interface Lengthwise {
      length: number;
    }
    function loggingIdentity<T extends Lengthwise>(arg: T): T {
      console.log(arg.length);
      return arg;
    }
    

    也可以使用含有泛型的接口来定义函数的形状:

    interface CreateArrayFunc {
      <T>(length: number, value: T): Array<T>;
    }
    let createArray: CreateArrayFunc;
    createArray = function<T>(length: number, value: T): Array<T> {
      let result = [];
      for (let i = 0; i < length; i++) {
        result[i] = value;
      }
      return result;
    }
    

    TypeScript 除了实现了所有 ES6 中的类的功能以外,还添加了一些新的用法

    TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected

    • public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
    • private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
    • protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

    abstract 用于定义抽象类和其中的抽象方法

    编译前
    abstract class Animal {
      public name;
      public constructor(name) {
        this.name = name;
      }
      public abstract sayHi();
    }
    
    class Cat extends Animal {
      public sayHi() {
        console.log(`Meow, My name is ${this.name}`);
      }
    }
    
    let cat = new Cat('Tom');
    
    编译后
    var __extends = (this && this.__extends) || function (d, b) {
        for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
    var Animal = (function () {
        function Animal(name) {
            this.name = name;
        }
        return Animal;
    }());
    var Cat = (function (_super) {
        __extends(Cat, _super);
        function Cat() {
            _super.apply(this, arguments);
        }
        Cat.prototype.sayHi = function () {
            console.log('Meow, My name is ' + this.name);
        };
        return Cat;
    }(Animal));
    var cat = new Cat('Tom');
    

    更多阅读资料

  • 相关阅读:
    HU 参考错误修正:/SCWM/RCORR_HUREF
    EWM 强大的数据修复功能
    EWM ODO清理功能
    发布EWM RF ITS Mobile 相关服务
    git上传本地Intellij idea 项目到码云的git仓库中
    linux 学习一:安装jdk和tomcat
    bootstrap-datepicker应用
    vue2 枚举类型转换
    jqGrid时间转换
    (原创)Rocketmq分布式消息队列的部署与监控
  • 原文地址:https://www.cnblogs.com/xlys/p/8085575.html
Copyright © 2020-2023  润新知