zoukankan      html  css  js  c++  java
  • 2.TypeScript 基础入门(二)

    变量类型的那些事

    1.基本注解

    类型注解使用:TypeAnnotation 语法。类型声明空间中可用的任何内容都可以用作类型注解。

    const num: number = 123;
    function identity(num:number):number{
        return num;
    }
    
    

    加入注解以后会报错的写法:

    const num: number = 123;
    function identity(num: number): number {
      const num1 = '123'
      // 返回的不是 number  报错
      return num1;
    }
    const num1 = '123' 
    // 参数不是 number 报错
    identity(num1)
    

    2. 原始类型

    Javascript原始类型也同样适用于 TypeScript的类型系统。因此,string, number,boolean也可以被用作类型注解:

     let num: number;
     let str: string;
     let bool: boolean;
    
     num = 123;
     num = 123.45;
     num = '123'; //Type '"123"' is not assignable to type 'number'
    
     str = '123';
     str = 123; //Type '123' is not assignable to type 'string'
    
     bool = true;
     bool = false;
     bool = 'false';//Type '"false"' is not assignable to type 'boolean'.
    

    3. 数组

    TypeScript 为数组提供了专用的类型语法,因此你可以很轻易的注解数组。它使用后缀[],接着你可以根据需要补充任何有效的类型注解(如:boolean[])。它能让你安全的使用任何有关数组的操作,而且它能放置一些类似赋值错误类型给成员的行为。

    你有两种定义数组的方式:

    第一种,你可以在元素类型后面接上[],表示由此类型元素组成的一个数组:

    let list:number[] = [1,2,3]
    

    第二种方式是使用数组泛型,Array<元素类型>:

    let list: Array<number> = [1,2,3]
    

    一个具体的栗子:

    const boolArray: boolean[];
    
    boolArray = [true, false];
    console.log(boolArray[0]); // true
    console.log(boolArray.length); // 2
    
    boolArray[1] = true;
    boolArray = [false, false];
    
    boolArray[0] = 'false'; // Error
    boolArray = 'false'; // Error
    boolArray = [true, 'false']; // Error
    

    4.元组

    元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。比如,你可以定义一对值分别为stringnumber类型的元组。

    // 声明一个元组类型
    let x: [string, number];
    // 初始化赋值
    x = ['hello', 10]; // OK
    // 初始化错误
    x = [10, 'hello']; // Error
    

    当访问一个已知索引的元素,会得到正确的类型:

    console.log(x[0].substr(1)); // OK
    console.log(x[1].substr(1)); // Error, 'number' does not have 'substr'
    

    ?????????
    当访问一个越界的元素,会使用联合类型替代:

    x[3] = 'world'; // OK, 字符串可以赋值给(string|number)类型
    

    但是我在编辑器里使用的时候是报错的,Index '2' is out-of-bounds in tuple of length 2,我也不知道为什么??

    5. 枚举

    enum 类型是对JavaScript 标准数据类型的一个补充。使用枚举类型可以为一组数值赋予友好的名字。

    enum Color {Red, Green, Blue}
    let c: Color = Color.Green;
    

    默认情况下,从0开始为元素编号。你也可以手动的指定成员的编号。例如,我们将上面的栗子改成从1开始编号:

    enum Color {Red = 1, Green, Blue}
    let c: Color = Color.Green;
    

    或者采用全部手动赋值:

    enum Color {Red = 1,Geeen = 2, Blue = 4}
    let c: Color = Color.Green
    

    编译后的js

    var Color;
    (function (Color) {
        Color[Color["Red"] = 1] = "Red";
        Color[Color["Green"] = 2] = "Green";
        Color[Color["Blue"] = 4] = "Blue";
    })(Color || (Color = {}));
    var c = Color.Green;
    

    所有的表达式都有返回值,它的返回值就是等号右边的赋值。

    枚举类型提供的一个遍历是你可以由枚举的值得到它的名字。
    例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:

    enum Color {Red = 1, Green, Blue}
    let colorName: string = Color[2];
    
    console.log(colorName);  // 显示'Green'因为上面代码里它的值是2
    

    这个试了一下不给数值number,发现没办法通过这个取值

    enum Color {Red = 'r', Green = 'g', Blue = 'b'}
    let c: Color = Color.Green;
    console.log(c) // g
    let colorName:string = Color[2]
    console.log(colorName) // undefined
    

    我们看一下编译后的javascript代码就明白了:

    var Color;
    (function (Color) {
       Color["Red"] = "r";
       Color["Green"] = "g";
       Color["Blue"] = "b";
    })(Color || (Color = {}));
    var c = Color.Green;
    console.log(c);
    var colorName = Color[2];
    console.log(colorName);
    

    6. 特殊类型

    6.1 any

    any类型在 TypeScript类型系统中占有特殊的地位。它提供给你一个类型系统的【后门】,TypeScript将会把类型检查关闭。在类型系统里any能够兼容所有的类型(包括它自己)。因此,所有的类型都能够被赋值给它。它也能被赋值给其他任何类型。

    let power: any;
    //赋值任意类型
    power = '123'
    power = 123
    let num:number;
    num = power;
    power = num;
    

    6.2 null 和 undefined

    在类型系统中,JavaScript 中的 null 和 undefined 字面量和其他被标注了 any 类型的变量一样,都能被赋值给任意类型的变量,如下例子所示:

    let num: numer;
    let str: string;
    
    // 这些类型能被赋予
    num = null;
    str = undefined;
    

    6.3 void

    使用 :void来表示一个函数没有一个返回值

    function log(message:string):void{
        console.log(message)
    }
    

    声明一个void类型的变量没有什么大用,因为你只能为它赋予undefinednull

    let unusable:void = undefined
    

    7.泛型

    软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。

    不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

    举一个简单的演变例子:

    当不实用泛型的时候,你的代码可能是像这样:

    function identity(arg:number):number{
        return arg;
    }
    

    这个函数可以接收number 类型,返回的也是number类型,考虑到这个函数的可重用性,或者,我们可以使用any类型来定义函数像这样:

    function identity(arg:any):any{
        return arg;
    }
    

    使用any类型会导致这个函数可以接受任何类型的arg参数,且任何类型的值都可能被返回。

    我们需要一种方法使返回值的类型与传入参数的类型是相同的。
    接下来我们可以把代码像下面这样:

    function identity<T>(arg:T):T{
        return arg
    }
    

    我们给 identity 添加了类型变量 T。 如果传入的类型(比如:number),我们就可以知道返回的类型也是number。现在我们就可以知道参数类型与返回值类型是相同的了。这有助于我们跟踪函数里使用的类型的信息。

    我们把这个版本的identity函数叫做 泛型。 它可以使用与多个类型,不同于使用any,的不确定性,还能保持像第一个例子一样的准确性参数类型返回值类型相同的。

    7.1 泛型的使用

    我们定义了泛型函数之火,可以使用两种方法使用。

    第一种是传入所有的参数,包含类型参数:

    let output = identity<string>('myString');//type of output will be 'string'
    

    这里我们明确的指定了Tstring类型,并做为一个参数传给函数,并且确定output的类型是string.

    注意⚠️:使用<>不是()

    第二种方法,利用类型推论--即编译器会根据传入的参数自动的帮助我们确定T的类型。

    let output = identity("myString");// type of output will be 'string'
    

    这里并没有使用(<>)来明确地传入类型;编译器可以查看myString的值,然后把T设置为它的类型。

    7.2 使用泛型变量

    使用泛型创建像identity这样的泛型函数时,编译器要求你在函数体必须正确的使用这个通用的类型。换句话说,你必须把这些参数当作时任意或所有类型。

    看下我们之前写的泛型例子:

    function identity<T>(arg:T):T{
        return arg
    }
    

    当我们试图在函数内输出arg.length的时候,编译器就会报错类型“T”上不存在属性“length”

    function idenfity<T>(arg:T):T{
     console.log(arg.length) // Error: T doesn't have .length
     return arg
    }
    

    注意⚠️:

    类型变量T代表的时任意类型,所以使用这个函数的人可能传入的是个数字,而数字时没有.length属性的。

    然后我们假设想操作T类型的数组而不直接是T,由于我们操作的是数组,此时.length的属性应该是存在。

    代码像这样:

    function loggingIdentity<T>(arg: T[]):T[]{
    console.log(arg.length) // Array has a .length,so no more error
    return arg
    }
    

    我们可以这样理解loggingIdentity的类型:泛型函数loggingIdentity,接收类型参数T和参数arg,它是个元素类型是T的数组,并返回元素类型T的数组。如果我们传入数字数组,将返回一个数字数组,因为此时T的类型为number。这可以让我们把泛型变量T当作类型的一部分使用,而不是整个类型,增加了灵活性。

    我们还可以这样实现上面的例子:

    function loggingIdentity<T>(arg:Array<T>):Array<T>{
    console.log(arg.length)
    return arg
    }
    

    在计算机科学中,许多算法和数据结构并不会依赖于对象的实际类型。然而,你仍然会想在每个变量里强制提供约束。

    例如:在一个函数中,它接受一个列表,并且返回这个列表的反向排序,这里的约束是指传入至函数的参数与函数的返回值:

    function reverse<T>(items:T[]):T[]{
      const toreturn = []
      for(let i = items.length - 1;i>=0;i--){
        toreturn.push(items[i])
      }
      return toreturn
    }
    
    const sample = [1,2,3]
    let reversed = reverse(sample)
    
    console.log(reversed)
    
    reversed[0] = '1'; // Error
    reversed = ['1', '2']; // Error
    
    reversed[0] = 1; // ok
    reversed = [1, 2]; // ok
    

    这个栗子中,函数reverse接受一个类型为T的数组items:T[],返回值为类型T的一个数组(注意:T[]),函数 reverse的返回值类型与它接受的参数类型一样。当你传入var sample = [1, 2, 3]时,TypeScript能推断出 reversenumber[]类型,从而能给你类型安全。于此相似,当你传递一个string[]类型的数组时,TypeScript能推断出为string[]类型,
    如:

    const strArr = ['1','2']
    let reversedStrs = reverse(strArr)
    reversedStrs = [1, 2]; // Error
    

    如果你的数组是const sample = [1,false,3]等同于const sample: (number | boolean)[],所以下面的代码也能可以的,如果是数组里有两种甚至三种类型的时候,它是能够推断出(number | boolean)这种或的类型的。也就是下面所说的联合类型。

    function reverse<T>(items:T[]):T[]{
      const toreturn = []
      for(let i = items.length - 1;i>=0;i--){
        toreturn.push(items[i])
      }
      return toreturn
    }
    
    const sample = [1,false,3]
    let reversed = reverse(sample)
    
    console.log(reversed)
    
    reversed[0] = true; // OK
    reversed = [3, true]; // OK
    
    reversed[0] = 1; // ok
    reversed = [1, 2]; // ok
    

    8.联合类型

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

    8.1简单的例子

    let myFavoriteNumber: string | number;
    myFavoriteNumber = 'seven'
    myFavoriteNumber = 7
    
    let myFavoriteNumber: string | number;
    myFavoriteNumber = true;
    
    // index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.
    //   Type 'boolean' is not assignable to type 'number'
    
    

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

    这里的let myFavoriteNumber: string | number;的含义是,允许myFavoriteNumber的类型是string或者number,但是不能是其他类型。

    8.2 访问联合类型的属性或方法

    TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里的共有的属性或方法

    function getLength(something:string|number):number{
    return something.length
    }
    // Error 类型“string | number”上不存在属性“length”。
      类型“number”上不存在属性“length”。
    

    上例中,length不是stringnumber的共有属性,所以会报错。

    访问stringnumber的共有属性是没问题的:

    function getLength(something:string|number):string{
        return something.toString()
    }
    

    联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:

    let myFavoriteNumber:string|number;
    myFavoriteNumber = 'seven';
    console.log(myFavoriteNumber.length)
    
    myFavoriteNumber = 7
    console.log(myFavoriteNumber.length) // Rrror 类型“number”上不存在属性“length”。
    
    

    上例中,第二行的myFavoriteNumber被推断成了string,访问它的length属性不会报错。而第四行的myFavoriteNumber被推断成了number,访问它的length属性时就报错了。

    一个常见的用例是一个可以接受单个对象或者对象数组的函数:

    function formatCommandline(command: string[] | string) {
      let line = '';
      if (typeof command === 'string') {
        line = command.trim();
      } else {
        line = command.join(' ').trim();
      }
    
      // Do stuff with line: string
    }
    
  • 相关阅读:
    hdu 1015 Safecracker 暴力搜索
    hdu 1239 Calling Extraterrestrial Intelligence Again 枚举
    hdu 3747 Download 菜鸟杯
    hdu 3744 A Runing Game 菜鸟杯
    Request.QueryString 使用时候应该注意的地方。
    图片 上一张 下一张 链接效果
    ASP.NET 输出缓存的移除
    RSS 消费
    RSS 订阅功能的实现
    创建型模式单件模式(1)
  • 原文地址:https://www.cnblogs.com/chenshufang/p/10276694.html
Copyright © 2011-2022 走看看