zoukankan      html  css  js  c++  java
  • TypeScript初识

    # 什么是typeScript
    - typeScript是javaScript的超集,主要提供了类型系统和对ES6的支持。
    - typeScript的代码通过 ts编译工具 可以编译成javaScript代码,从而能在浏览器上运行。类似于java代码需要变成class文件。
    - ts代码 => js代码 需要编译, js代码 => ts代码 直接改后缀名为.ts即可,这也是因为ts是js的超集,它包含js但不限于js。

    # ts的编译工具
    - 上面有提到ts要在浏览器上运行必须编译成js,这里就需要使用ts的编译工具,这个工具其实就是在全局安装tpeyScript。命令如下
    -- npm install -g typescript
    -- 安装之后我们可以在命令行使用 tsc 命令(类似与javac) 对ts文件进行编译。
    -- 例如编译 hello.ts 文件,在命令行执行: tsc hello.ts 命令。这时你的目录里面就会生产一个hello.ts编译之 后的js文件 hello.js

    # ts 初体验
    - 我们先编写一个hello.ts文件,代码如下
    ```javaScript (ts)
    function sayHello(person: string) {
    return 'Hello, ' + person;
    }
    let userName = 'world';
    console.log(sayHello(userName));
    ```
    - 再进行编译 得到hello.js文件,代码如下
    ```javaScript
    function sayHello(person) {
    return 'Hello, ' + person;
    }
    var userName = 'world';
    console.log(sayHello(userName));
    ```
    1. 我们可以看到ts代码中sayHello函数的参数为person: string,规定了只能是字符串类型。如果你传入的是其他类型,编译的时候会编译,但是会报错。

    # 基本数据类型
    - 和js中一样ts也包含布尔值,数值,字符串,null,undefined这集中基本数据类型。当然还有es6中提供的Symbol类型。

    ## 布尔值类型
    - 布尔值作为基本类型中的一种,在ts中使用boolean定义布尔值,注意,不是Boolean,在上面ts初体验中我们定义参数使用的也是string,而不是String

    ```javaScript (ts)
    let isShow : boolean = false; //这里是可以编译通过的
    ```
    - 如果我们ts中像js一样使用构造函数的方法定义一个布尔值是会报错的
    ```javaScript
    let createdByNewBoolean: boolean = new Boolean(1);
    // index.ts(1,5): error TS2322: Type 'Boolean' is not assignable to type 'boolean'.
    /**
    * 事实上在ts中boolean表示的是基本数据类型呢,let createdByNewBoolean: boolean 实际上就是规定了createdByNewBoolean只能是boolean类型。
    * 而Boolean无论是在js中还是ts中他都是一个构造函数,通过new构造函数的方式得到值就是一个对象,而对象是属于引用数据类型。
    * 其实在js中也是一样,只是js没有如此严格类型系统。
    * 这一点ts的基本类型中其他基本类型都是一样,后面就不再赘述(除了null和undefined)
    */

    ```
    ## 数值类型
    - ts中使用number定义数值类型,直接上代码吧
    ```javaScript (ts)
    let decLiteral: number = 6;
    // 十六进制
    let hexLiteral: number = 0xf00d;
    // ES6 中的二进制表示法
    let binaryLiteral: number = 0b1010;
    // ES6 中的八进制表示法
    let octalLiteral: number = 0o744;
    let notANumber: number = NaN;
    let infinityNumber: number = Infinity;
    ```
    -以上ts代码经过编译之后
    ```javaScript
    var decLiteral = 6;
    // 十六进制数
    var hexLiteral = 0xf00d;
    // ES6 中的二进制表示法
    var binaryLiteral = 10;
    // ES6 中的八进制表示法
    var octalLiteral = 484;
    var notANumber = NaN;
    var infinityNumber = Infinity;
    /**
    * 我们可以看到ts经过编译以后,2进制,8进制都被转化成了10进制数。16进制没有。
    * 为啥16进制不转呢?
    * Infinity是啥?简单的说(复杂的我也不会)他是表示所有超出javaScript处理范围的数值。他可以进行运算,但是结果不是Infinity(加)就是NaN(乘除减)。
    * 我们知道数学中0不能作为除数,任何数除以0都是没有意义的。在js中也是一样,任何数除以0得到的值都是Infinity包括Infinity本身(0除外,0/0=NaN)。
    */
    ```
    ## 字符串类型
    - 前面有提到ts中使用string来定义字符串

    ```javaScript (ts)
    let myName: string = 'Tom';
    let myAge: number = 25;
    // 模板字符串
    let sentence: string = `Hello, my name is ${myName}.I'll be ${myAge + 1} years old next month.`;
    ```
    - 以上ts代码编译之后得到以下js代码
    ```javaScript
    var myName = 'Tom';
    var myAge = 25;
    // 模板字符串
    var sentence = "Hello, my name is " + myName + ". I'll be " + (myAge + 1) + " years old next month.";
    /**
    * 我们可以到定义的方式语法和数值布尔值类型是一样的,平时我们工作也会使用到es6中模版字符串,使用``包裹模版,${}包裹变量
    * 编译之后就回到了我们js中相对low逼的字符串拼接模式。
    */
    ```
    ## 空值(ts新增基本类型)
    - ts中使用viod来定义空值,但是我们一般不会去定义一个空值,因为你只能给他赋值null或者undefined。
    - 我们可以用viod来表示一个函数没有没有任何返回值

    ```javaScript (ts)
    let unusable: void = undefined; // 你只能给他赋值unll和undefined
    function alertName(): void { //这表示alertName函数没有任何返回值
    alert('My name is Tom');
    }
    ```
    ## null和undefined
    - 这是两种基本数据类型,由于特点相似所以放在一起讲
    - null和undefined 是所有类型的子类型,也就是说,不论你定义的任何数据类型的变量都可以赋值null和undefined。
    - 这也是null/undefined 和 空值viod的不同之处,被定义为viod类型的变量是不能赋值到其他类型的数据的。
     
    ```javaScript (ts)
    /**
    * 我们前面提到定义void的变量可以给他赋值null和undefined的,
    * unll和undefined可以赋值给任何类型的变量,那么我先给void变量u赋值unll, 再将变量u赋值给数值类型n会不会报错呢?
    * 如下列代码,是会报错的。
    */

    let u:void = null
    let n:number = u

    let a:number = null
    ```

    ## 任意值
    - 任意值在ts中使用any定义。
    - 个人理解是和js中定义变量一样,当你规定这个变量是一个any类型的时候,你可以给他赋值任何类型的数据。
    - 对任意值类型进行任何操作得到的数据都是任意值类型。

    ```javascript (ts)
    let myFavoriteNumber: any = 'seven';
    myFavoriteNumber = 7;
    console.log(myFavoriteNumber);
    myFavoriteNumber = [];
    console.log(myFavoriteNumber);
     
    /**
    * 当定义后没有马上赋值,并且没有定义类型。默认为任意类型
    */

    let arry;
    arry = 0;
    console.log(arry);
    arry = [1,2,3]
    console.log(arry);
    ```
    ```javascript
    var myFavoriteNumber = 'seven';
    myFavoriteNumber = 7;
    console.log(myFavoriteNumber);
    myFavoriteNumber = [];
    console.log(myFavoriteNumber);
    /**
    * 当定义后没有马上赋值,并且没有定义类型。默认为任意类型
    */
    var arry;
    arry = 0;
    console.log(arry);
    arry = [1, 2, 3];
    console.log(arry);
    ```
    ### 类型推论,恰好讲到任意类型先定义后赋值,该定义数据默认为any类型,Ts中还有类型推论规则
    - 当你定义数据没有定义类型的时候,并且在定义的同时给他赋值了,那么ts就会推论,你这个数据为你所赋值的类型。
    - 这里需要和上面先定义后赋值的情况区分。
    - let arry; ==> arry 为任意值类型, let arry = '123' ==> arry 为字符串类型,后续也只能使用字符串为他赋值

    ## 联合类型
    - 顾名思义,表示取值可以为多种类型之一
    - 定义类型时使用 | 将类型隔开
    ```javascript (ts)
    let lianhe: string | number = 3;
    lianhe = 'seven';
    lianhe = 7;
    ```
    ```javascript
    var lianhe = 3;
    lianhe = 'seven';
    lianhe = 7;
    ```
    ### 访问联合属性的类型和方法

    ```javascript (ts)
    /**
    * something是一个联合类型,他可以是string,也可以是number
    * 在函数getLength中我们我们尚不清楚他传入的是什么类型,所以只能调取string和number的公共属性或者方法。
    *
    */
    function getLength(something: string | number){
    // return something.length; // 报错
    return something.toString(); // 不报错
    }
    /**
    * 联合类型也适用类型推论
    */
    let abc : string | number;
    abc = 100 ; // 此时犹豫类型推论原则,ts认为abc是一个数字
    // console.log(abc.length) // 报错
    abc = 'hello' ;
    console.log(abc.length) // 5
    ```

    # 引用类型

    ## 对象的类型-接口
    - 在ts中我们使用interfaces来定义对象的类型
    - 什么是对象的类型,我是这么理解,他是一个规则,假设你通过某个接口去定义了一个对象,那么这个对象必须按照这个接口规则去写。
    - 教程中原文是这么说:TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。
    - 一个简单的例子
    ```javascript
    // 定义接口
    interface Person { // 接口一般首字母大写。有的编程语言中会建议接口的名称加上 I 前缀。
    name: string;
    age: number;
    }
    // 通过定义的接口,来约束对象(定义对象)
    let tom: Person = {
    name: 'Tom',
    age: 25
    };
    ```
    ### 接口特点
    1. 固定属性-当你使用接口去约束你定义的对象后,你为你对象定义的属性/方法,都应该和接口一致,包括数量和命名
    2. 可选属性-约束得太死难免会有不愉快的事情发生,所以接口允许设置可选属性, 属性名后面加一个问号即可。
    - 可选属性可以不存在。
    3. 任意属性
    - 使用 [propName: string] 定义了任意属性取 string 类型的值。
    - 需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
    - 目前我认为这个属性有点鸡肋,放开一个属性,限制了可选属性和确定属性。
    4. 只读属性
    - 通过readonly定义只读属性
    - 只读属性必须在定义类的时候定义并赋值,后期不可修改。

    ## 数组类型
    1. 在ts中数组类型的定义有很多种
    - 「类型 + 方括号」表示法
    - 规定了数组成员的类型,不能在该数组中添加其他类型属性(null和undefined除外,上面有讲,他是其他类型子集)
    ```javascript (ts)
    let arryList:number[] = [1,2,3,4,5] // 定义arrayList为一个数值数组
    console.log(arryList);
    arryList.push(10);
    arryList.push(null);
    arryList.push(undefined);
    // arryList.push('1'); // 往里面添加字符串是会报错的。
    console.log(arryList);
    // 当然如果你定义的类型为any,那你就可以随意push进任意数据类型了
    ```
    2. 用接口定义数组 (接口是用来定义对象的类型和形状的。万物皆对象,数组也是对象咯)

    ```javascript (ts)
    interface NewArry {
    [a : number] : number; //定义这个数组对象的每一项只能是数值
    }
    let arr1:NewArry = [1,2,3,4,"1"];
    ```
    3. 还有一种方式叫做数组泛型,在此不做分享,后面进阶内容有详细解说。

    ## 类数组
    - 类数组不属于数组类型,比如arguments:
    - 事实上常见的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等:
    ```javascript (ts)
    function sum() {
    let args: number[] = arguments; // 会报错
    }
    function sum2() {
    let args: IArguments = arguments; // 使用他们自己的接口定义就不会报错
    }
    ```

    ## 函数
    - 在ts中函数也和js中一样,使用函数声明和函数表达式定义函数
    - 不同的是ts对函数输入和输出进行了更多的约束
    1. 定义规则
    - 输入多余的(或者少于要求的)参数,是不被允许的。
    2. 函数声明
    ```javascript (ts)
    function fn1( x : number,y : number ) : number {
    return x+y
    }
    ```
    3. 函数表达式
    ```javascript (ts)
    /**
    * 这里的 => 要和es6中的箭头函数区分,=> 在这里 左边表示函数的参数定义,右边表示函数的返回值定义。
    */
    let fn2 : ( x: number, y : number ) => number = function( x: number, y: number) : number {
    return x+y
    }
    ```
    4. 接口定义函数
    ```javascript (Ts)
    // 定义接口
    interface SearchFunc {
    (source: string, subString: string): boolean;
    }
    // 接口约束函数
    let fn3: SearchFunc;
    fn3 = function(source: string, subString: string) {
    return source.search(subString) !== -1;
    }
    ```

    5. 可选参数
    - 可选参数使用 ?标识
    - 需要注意的是,可选参数必须接在必需参数后面。换句话说,可选参数后面不允许再出现必须参数了
    ```javascript (ts)
    function fn4(firstName: string, lastName?: string) {
    if (lastName) {
    return firstName + ' ' + lastName;
    } else {
    return firstName;
    }
    }
    let tomcat = fn4('Tom', 'Cat');
    let tom = fn4('Tom');
    ```

    6. 参数默认值
    - 在 ES6 中,我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数
    - 此时就不受「可选参数必须接在必需参数后面」的限制了
    ```javascript (Ts)
    function fn5(firstName: string = 'Tom', lastName: string) {
    return firstName + ' ' + lastName;
    }
    let tomcat = fn5('Tom', 'Cat');
    let cat = fn5(undefined, 'Cat');
    ```
    7. 剩余参数
    - ES6 中,可以使用 ...rest 的方式获取函数中的剩余参数(rest 参数)
    - 剩余参数只能是最后一个参数
    ```javascript (Ts)
    function push1(array, ...items) {
    items.forEach(function(item) {
    array.push(item);
    });
    }

    let a = [];
    push(a, 1, 2, 3);
    // 事实上,剩余参数 items 是一个数组。所以我们可以用数组的类型来定义它:
    function push2(array: any[], ...items: any[]) {
    items.forEach(function(item) {
    array.push(item);
    });
    }

    let a = [];
    push2(a, 1, 2, 3);
    ```

    8. 重载
    - 什么是重载,就是函数的方法名相同,但是参数不同,调用的时候根据参数的不同去执行不同的执行体。
    - js中不存在重载,如果方法名相同,他永远执行的是写在最后的一个方法。
    - 重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
    - 比如,我们需要实现一个函数 reverse,输入数字 123 的时候,输出反转的数字 321,输入字符串 'hello' 的时候,输出反转的字符串 'olleh'。
    - 利用联合类型,我们可以这么实现
    ```javascript (Ts)
    function reverse1( x: string | number) : number|string{
    if( typeof x === 'number') {
    return Number(x.toString().slipt('').reverse().join(''))
    }else if(typeof x === 'string'){
    return x.slipt('').reverse().join('')
    }
    }
    /**
    * 然而这样有一个缺点,就是不能够精确的表达,输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串。这时,我们可以使用重载定义多个 reverse 的函数类型
    */
    function reverse2(x: number): number;
    function reverse2(x: string): string;
    function reverse2(x: number | string): number | string {
    if (typeof x === 'number') {
    return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
    return x.split('').reverse().join('');
    }
    }
    /**
    * 上例中,我们重复定义了多次函数 reverse,前几次都是函数定义,最后一次是函数实现。
    * 注意,TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面
    */
    ```
    ## 类型断言
    1. 语法
    - <类型>值
    - 值 as 类型 ==> 在 tsx 语法(React 的 jsx 语法的 ts 版)中必须用后一种。

    2. 意义
    - 之前提到过,当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法
    - 这时我们就可以使用类型断言,将一个联合类型的变量指定为一个更加具体的类型,从而使用这个类型的属性

    3. 类型断言,不是类型转换,断言一个联合类型中不存在的类型是会报错的。

    ```javascript (ts)
    function getLength(something: string | number): number {
    if (something.length) {
    return something.length;
    } else {
    return something.toString().length;
    }
    }
    // 以上代码是会报错的。在没有断言的情况下,只能直接访问联合类型的公共属性
    function getLength(something: string | number): number {
    if ((<string>something).length) {
    return (<string>something).length;
    } else {
    return something.toString().length;
    }
    }
    ```
    ## 内置对象
    1. JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。
    - 内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准。

    2. ECMAScript
    - 标准提供的内置对象有 : Boolean、Error、Date、RegExp 等
    - 我们可以在 TypeScript 中将变量定义为这些类型:
    ```javascript (ts)
    let b: Boolean = new Boolean(1);
    let e: Error = new Error('Error occurred');
    let d: Date = new Date();
    let r: RegExp = /[a-z]/;
    ```
    3. DOM 和 BOM 提供的内置对象有:Document、HTMLElement、Event、NodeList 等。
    ```javascript (ts)
    let body: HTMLElement = document.body;
    let allDiv: NodeList = document.querySelectorAll('div');
    document.addEventListener('click', function(e: MouseEvent) {
    // Do something
    });
    ```
    4. 使用ts写node.js
    - Node.js 不是内置对象的一部分,如果想用 TypeScript 写 Node.js,则需要引入第三方声明文件:
    npm install @types/node --save-dev


  • 相关阅读:
    Redis源代码分析(十三)--- redis-benchmark性能測试
    kvm中运行kvm
    umount.nfs device busy day virsh extend diskSpace, attachDisk
    ultravnc
    openNebula dubug
    maintenance ShellScripts
    virsh VMI deploy data serial xml
    cloud computing platform,virtual authentication encryption
    基于C 的libvirt 接口调用
    storage theory
  • 原文地址:https://www.cnblogs.com/boye-1990/p/11039862.html
Copyright © 2011-2022 走看看