• TypeScripe学习


    原始数据类型

    原始数据类型包括:布尔值、数值、字符串、nullundefined 以及 ES6 中的新类型 Symbol

    在TS中,使用 : 指定变量的类型

    1.布尔值

    let isDone: boolean = false;

    事实上 new Boolean() 返回的是一个 Boolean 对象:

    let createdByNewBoolean: Boolean = new Boolean(1);

    直接调用 Boolean 也可以返回一个 boolean 类型

    let createdByBoolean: boolean = Boolean(1);

    错误的写法

    let createdByNewBoolean: boolean = new Boolean(1);//错误写法
    let createdByNewBoolean: Boolean = new Boolean(1);//正确写法

    2.数值

    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;    

    编译结果:

    var decLiteral = 6;
    var hexLiteral = 0xf00d;
    // ES6 中的二进制表示法
    var binaryLiteral = 10;
    // ES6 中的八进制表示法
    var octalLiteral = 484;
    var notANumber = NaN;
    var infinityNumber = Infinity;

    3.字符串

    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.`;

    编译结果:

    var myName = 'Tom';
    var myAge = 25;
    // 模板字符串
    var sentence = "Hello, my name is " + myName + ".
    I'll be " + (myAge + 1) + " years old next month.";

    4.null和undefined

    null和undefined在typescript中分别是两个独立的类型限定:

     let u: undefined = undefined;
     let n: null = null;     

    undefined限定的变量只能赋值undefined,null也一样。

    void 的区别是,undefinednull 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量

    5.空值void

    void限定的变量只能赋值null或者undefined

    let unusable: void = undefined;

    与null和undefined限定不同的是,null和undefined是所有类型的子类型:

    let num: number = undefined; //这样没有问题
    // 这样也不会报错
    let u: undefined;
    let num: number = u;

    而void类型的变量不能互相随意传递:

    let noContent: void;
    let num: number = noContent; // 报错

     

    任意值 any

    允许赋值为任意类型

    let myFavoriteNumber: any = 'seven';
    myFavoriteNumber = 7;

    声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值

    变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型

    类型推论

    如果没有明确的指定类型,那么 TypeScript 会依照类型推论的规则推断出一个类型。

    let myFavoriteNumber = 'seven';
    myFavoriteNumber = 7;
    
    // 等价于下边
    let myFavoriteNumber: string = 'seven';
    myFavoriteNumber = 7;

    TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论。

    如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查

    let myFavoriteNumber;
    myFavoriteNumber = 'seven';
    myFavoriteNumber = 7;

    联合类型

    表示取值可以为多种类型中的一种

    联合类型使用 | 分隔每个类型

    let myFavoriteNumber: string | number;
    myFavoriteNumber = 'seven';
    myFavoriteNumber = 7;

    对象的类型——接口

    在 TypeScript 中,我们使用接口来定义对象的类型

    在面向对象语言中,接口是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类去实现。

    1.简单的例子

    interface Person {
        name: string;
        age: number;
    }
    
    let tom: Person = {
        name: 'Tom',
        age: 25
    };

    上面的例子中,我们定义了一个接口 Person,接着定义了一个变量 tom,它的类型是 Person。这样,我们就约束了 tom 的形状必须和接口 Person 一致。

    定义的变量不允许多一个属性或者少一个属性。

    赋值的时候,变量的形状必须和接口的形状保持一致。

    2.可选属性

    interface Person {
        name: string;
        age?: number;  //可选属性
    }

    可选属性的含义是该属性可以不存在。

    但是仍然不允许添加未定义的属性。

    3.任意属性

    interface Person {
        name: string;
        age?: number;
        [propName: string]: any;  //任意属性
    }
    
    let tom: Person = {
        name: 'Tom',
        gender: 'male'
    };

    使用 [propName: string] 定义了任意属性取 string 类型的值。

    注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集

    interface Person {
        name: string;
        age?: number;
        [propName: string]: string;//任意属性的值允许是 string
    }
    
    let tom: Person = {
        name: 'Tom',
        age: 25,
        gender: 'male'
    };

    上例中,任意属性的值允许是 string,但是可选属性 age 的值却是 numbernumber 不是 string 的子属性,所以报错了。

    4.只读属性

    interface Person {
        readonly id: number; //只读属性
        name: string;
        age?: number;
        [propName: string]: any;
    }
    
    let tom: Person = {
        id: 89757,
        name: 'Tom',
        gender: 'male'
    };
    //tom.id = 9527; //这里不允许给只读属性赋值,否则会报错

    注意:只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

    数组的类型

    1.「类型 + 方括号」表示法

    let fibonacci: number[] = [1, 1, 2, 3, 5];
    let fibonacci2: string[] = ['1', '1', '2', '3', '5'];
    fibonacci.push('9')  //报错,fibonacci不是string类型
    fibonacci2.push('9')

    2.数组泛型

    let fibonacci3: Array<number> = [1, 1, 2, 3, 5];
    let fibonacci4: string[] = ['1', '1', '2', '3', '5'];
    fibonacci3.push('9')  //报错,fibonacci3不是string类型
    fibonacci4.push('9')

    注意:在声明变量时,指定的变量为number,就不允许往其添加其他类型的值

    3.用接口表示数组

    interface NumberArray {
        [index: number]: number;
    }
    let fibonacci: NumberArray = [1, 1, 2, 3, 5];

    NumberArray 表示:只要索引的类型是数字时,那么值的类型必须是数字

    4.any在数组中的运用

    let list: any[] = ['xcatliu', 25, { website: 'abc' }];

    用any表示数组中允许出现任意类型

    5.类数组

    ...

    函数的类型

    1.函数声明

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

    注意:输入多余或者少于的参数,是不允许的。

    2.函数表达式

    let mySum = function (x: number, y: number): number {
        return x + y;
    };

    如果我们手动给sum添加类型,则应该是:

    let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
        return x + y;
    };

    注意:此处的=>符号和ES6中的=>符号不一样。在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。在 ES6 中,=> 叫做箭头函数。

    3.用接口定义函数的形状

    interface SearchFunc {
        (source: string, subString: string): boolean;
    }
    
    let mySearch: SearchFunc;
    mySearch = function(source: string, subString: string) {
        return source.search(subString) !== -1;
    }

    4.可选参数

    与接口中的可选属性类似,我们用 ? 表示可选的参数

    function buildName(firstName: string, lastName?: string) {
        if (lastName) {
            return firstName + ' ' + lastName;
        } else {
            return firstName;
        }
    }
    let tomcat = buildName('Tom', 'Cat');
    let tom = buildName('Tom');

    注意:可选参数必须接在必须参数后面,就是说可选参数后面不允许出现必须参数

    function buildName(firstName?: string, lastName: string) {
        if (firstName) {
            return firstName + ' ' + lastName;
        } else {
            return lastName;
        }
    } // 报错

    5.参数默认值

    TypeScript 会将添加了默认值的参数识别为可选参数

    function buildName(firstName: string, lastName: string = 'Cat') {
        return firstName + ' ' + lastName;
    }
    let tomcat = buildName('Tom', 'Cat');
    let tom = buildName('Tom');

    此时就不受「可选参数必须接在必需参数后面」的限制了

    function buildName(firstName: string = 'Tom', lastName: string) {
        return firstName + ' ' + lastName;
    }
    let tomcat = buildName('Tom', 'Cat');
    let cat = buildName(undefined, 'Cat');

    6.剩余参数

    ES6 中,可以使用 ...rest 的方式获取函数中的剩余参数(rest 参数)

    function push(array, ...items) {
        items.forEach(function(item) {
            array.push(item);
        });
    }
    
    let a = [];
    push(a, 1, 2, 3);

    注意:rest参数只能是最后一个参数,关于 rest 参数,可以参考 ES6 中的 rest 参数

    7.重载

    重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。

    function reverse(x: number): number;
    function reverse(x: string): string;
    function reverse(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 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。

    类型断言

    用来手动指定一个值的类型

    语法

    <类型>值
    

      或

    值 as 类型
    

     在 tsx 语法(React 的 jsx 语法的 ts 版)中必须用后一种。 

    使用场景

    之前有个例子当函数变量使用联合类型,如果我们在函数体中需要特定类型的方法,就需要使用类型断言,不然编译的时候就会报错:

    function getLength(something: string | number): number {
        if ((<string>something).length) {
            return (<string>something).length; //不加类型断言就会报错
        } else {
            return something.toString().length;
        }
    }

    注意,类型断言不是类型转换,断言一个联合类型不存在的类型会报错:

    function toBoolean(something: string | number): boolean {
        return <boolean>something; // 报错, 布尔类型不能赋值给something
    }

    内置对象

    参考地址:https://ts.xcatliu.com/basics/built-in-objects

    类型别名

    用来给一个类型起个新名字

    type Name = string;
    type NameResolver = () => string;
    type NameOrResolver = Name | NameResolver;
    function getName(n: NameOrResolver): Name {
        if (typeof n === 'string') {
            return n;
        } else {
            return n();
        }
    }
    console.log(getName('123456'))    //123456

    上例中,我们使用 type 创建类型别名。

    类型别名常用于联合类型。

     

    字符串字面量类型

    用来约束取值只能是某几个字符串中的一个

    type EventNames = 'click' | 'scroll' | 'mousemove';
    function handleEvent(ele: Element, event: EventNames) {
        // do something
    }
    
    handleEvent(document.getElementById('hello'), 'scroll');  // 没问题
    handleEvent(document.getElementById('world'), 'dbclick'); // 报错,event 不能为 'dbclick',只能为EventNames中的其中一个
    
    

    注意:类型别名与字符串字面量类型都是使用 type 进行定义。

     

    元组

    数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。

    1.例子

    
    
    let tom: [string, number] = ['Tom', 25];
    //或者 let tom2: [string, number]; tom2[0] = 'Tom'; tom2[1] = 25; tom2[0].slice(1); tom2[1].toFixed(2);
    //也可以只赋值其中一项 let tom3: [string, number]; tom3 = ['Tom', 25];

    2.越界的元素

    当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型

    let tom5: [string, number];
    tom5 = ['Tom', 25];
    tom5.push('male');
    // tom5.push(true); //报错,只能添加上面声明的类型

    枚举

    枚举类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。

    1.简单的例子

    枚举使用 enum 关键字来定义

    枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:

    enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
    
    console.log(Days["Sun"] === 0); // true
    console.log(Days["Mon"] === 1); // true
    console.log(Days["Tue"] === 2); // true
    console.log(Days["Sat"] === 6); // true
    
    console.log(Days[0] === "Sun"); // true
    console.log(Days[1] === "Mon"); // true
    console.log(Days[2] === "Tue"); // true
    console.log(Days[6] === "Sat"); // true
    
    //编译成
    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 = {}));

    2.手动赋值

    enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};
    
    console.log(Days["Sun"] === 7); // true
    console.log(Days["Mon"] === 1); // true
    console.log(Days["Tue"] === 2); // true
    console.log(Days["Sat"] === 6); // true

    未手动赋值的枚举项会接着上一个枚举项递增

    如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 是不会察觉到这一点的:

    enum Days {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};
    
    console.log(Days["Sun"] === 3); // true
    console.log(Days["Wed"] === 3); // true
    console.log(Days[3] === "Sun"); // false
    console.log(Days[3] === "Wed"); // true

    上面的例子中,递增到 3 的时候与前面的 Sun 的取值重复了,但是 TypeScript 并没有报错,导致 Days[3] 的值先是 "Sun",而后又被 "Wed" 覆盖了。编译的结果是:

    var Days;
    (function (Days) {
        Days[Days["Sun"] = 3] = "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 = {}));

    所以使用的时候需要注意,最好不要出现这种覆盖的情况。

    手动赋值的枚举项可以不是数字,此时需要使用类型断言来让 tsc 无视类型检查 (编译出的 js 仍然是可用的)。

    enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"S"};
    
    //编译成
    var Days;
    (function (Days) {
        Days[Days["Sun"] = 7] = "Sun";
        Days[Days["Mon"] = 8] = "Mon";
        Days[Days["Tue"] = 9] = "Tue";
        Days[Days["Wed"] = 10] = "Wed";
        Days[Days["Thu"] = 11] = "Thu";
        Days[Days["Fri"] = 12] = "Fri";
        Days[Days["Sat"] = "S"] = "Sat";
    })(Days || (Days = {}));

    手动赋值的枚举项也可以为小数或负数,此时后续未手动赋值的项的递增步长仍为 1。

    enum Days {Sun = 7, Mon = 1.5, Tue, Wed, Thu, Fri, Sat};
    
    console.log(Days["Sun"] === 7); // true
    console.log(Days["Mon"] === 1.5); // true
    console.log(Days["Tue"] === 2.5); // true
    console.log(Days["Sat"] === 6.5); // true

    3.常数项和计算所得项

    枚举项有两种类型:常数项和计算所得项。

    前面我们所举的例子都是常数项,一个典型的计算所得项的例子:

    enum Color {Red, Green, Blue = "blue".length};

    上面的例子中,"blue".length 就是一个计算所得项。

    上面的例子不会报错,但是如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错

    enum Color {Red = "red".length, Green, Blue};
    
    // index.ts(1,33): error TS1061: Enum member must have initializer.
    // index.ts(1,40): error TS1061: Enum member must have initializer.

    4.常数枚举

    使用 const enum 定义的枚举类型

    const enum Directions {
        Up,
        Down,
        Left,
        Right
    }
    
    let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];   //打印结果为[0,1,2,3]

    常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员。

    假如包含了计算成员,则会在编译阶段报错:

    const enum Color {Red, Green, Blue = "blue".length};
    
    // index.ts(1,38): error TS2474: In 'const' enum declarations member initializer must be constant expression

    5.外部枚举

    使用 declare enum 定义的枚举类型

    declare enum Directions {
        Up,
        Down,
        Left,
        Right
    }
    
    let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

    之前提到过,declare 定义的类型只会用于编译时的检查,编译结果中会被删除。

    上例的编译结果是:

    var directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

    外部枚举与声明语句一样,常出现在声明文件中。

    同时使用 declareconst 也是可以的:

    declare const enum Directions {
        Up,
        Down,
        Left,
        Right
    }
    
    let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

    编译结果:

    var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];

    TypeScript 的枚举类型的概念来源于 C#

     

     

  • 相关阅读:
    递归函数之阶乘和字符串反转-基于R和Python
    ERROR getting 'android:label' attribute: attribute is not a string value
    CefGlue 学习杂记
    WinDbg 解决Font.ToLogFont AccessViolationExcetion
    使用ActivityManager的forceStopPackage方法结束进程
    (转) lucene+paoding亲密接触
    (转)Lucene中文分词图解
    (转)实战 Lucene,第 1 部分: 初识 Lucene
    Python时间戳的使用
    Andriod中Style/Theme原理以及Activity界面文件选取过程浅析
  • 原文地址:https://www.cnblogs.com/chensv/p/12202052.html
Copyright © 2020-2023  润新知