【TypeScript】数据类型

183 阅读4分钟

原始数据类型

布尔值、数字、字符串、null、undefined、Symbol(ES6)、BigInt(ES10)

// 布尔值
let isDone: boolean = false;

// 数字
let decLiteral: numbe = 6;
let notAnNumber: number = NaN;
let infinityNumber: number = Infinity;
let binaryLiteral: number = 0b1010; // ES6 中的二进制表示法

// 字符串
let myName: string = 'Tom';
let sentence: string = `Hello, my Name is ${myName}`;

// 空值 void:表示没有任何返回值的函数;仅能赋值为null/undefined的变量
function alertName(): void {
  alert('My name is Tom!');
}
let unusable: void = undefined;

注意:

  1. 使用构造函数Boolean创造(new)的对象不是布尔值,返回的是一个Boolean对象。直接调用Boolean返回一个boolean类型。同理其他基本类型(除了null 和 undefined)。

     let createByNewBoolean: Boolean = new Boolean(1);
     let createByBoolean: boolean = Boolean(1)
    
  2. void 和 null / undefined 的区别

    undefined 和 null 是所有类型的子类型,可以赋值给number / string ... 类型的变量(需要在 tsconfig.json 配置文件中 "strict": false;),但是void不行。

    let num: number = undefined;
    ​
    let u = undefined;
    let num: number = u;
    ​
    let v = void;
    let num: number = v; 
    // Type 'void' is not assignable to type 'number'.
    

任意值(any)

允许赋值为任何类型

  1. 声明为任意值的变量,对它的任何操作,返回的内容类型都是任意值;
  2. 声明时未指定类型的变量,默认为任意值类型;
  3. 如果定义的时候没有赋值,之后不管有没有赋值,都会被推断成any类型而不被类型检查。

类型推论(Type Inference)

TypeScript 会在没有明确指定类型的时候推测出一个类型

let myNumber = 'seven';
myNumber = 7;
// Type 'number' is not assignable to type 'string'.
​
// ----- 等价于 -----
let myNumber: string = 'seven';
myNumber = 7;
​
// ----- 声明不赋值默认为any类型 ----
let myNumber;
myNumber = 'seven';
myNumber = 7;

联合类型(Union Types)

使用 | 分隔每个类型,取值可以为多种类型中的一种

  1. 在不确定联合类型的变量类型时,只能访问联合类型的所有类型里共有的属性和方法;
  2. 联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型;在赋值类型变化时可能导致报错。

对象的类型 —— 接口(Interfaces)

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

// 建议接口的名称加上I前缀
interface IPerson {
  readonly id: number, // 只读属性
  name: string; 
  age?: number; // 可选属性
  [key: string]: any // 任意属性
}

let tom: IPerson = {
  id: 1,
  name: 'Tom',
  age: 25
}

说明:

只读属性的约束在第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候。

```
interface IPerson {
  readonly id: number
  name: string
}

let tom: IPerson = {
  name: 'Tom'
}

tom.id = 1212; // error
```

数组的类型

// 1. 类型 + 方括号表示
let arr1: number[] = [1, 3, 4];

// 2. 数组泛型
let arr2: Array<number> = [1, 2, 3];

// 3. 接口表示(较复杂,很少用来表示数组)
interface INumberArray {
  [index: number]: number
}
let arr3: INumberArray = [1, 3, 4];

接口表示类数组

// 类数组转成数组
args = Array.prototype.slice.call(arguments)

函数的类型

函数声明

// ****** JavaScript ******

// 函数声明(Function Declaration)
function Sum(x, y) {
  return x + y;
}

// 函数表达式(Function Expression)
let mySum = function(x, y) {
  return x + y;
}

// ***** TypeScript ******
// 参数必须和声明时的对应,不可以多也不可以少
function Sum(x: number, y: number): number {
  return x + y;
}

let mySum = function (x: number, y: number): number {
  return x + y;
} // mySum 通过赋值操作进行类型推断获得

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

// (x: number, y: number) 输入定义 => number 输出定义

用接口定义函数的形状

interface SearchFunc {
	(source: string, subString: string): boolean;
}

let mySearch: SearchFunc;

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

可选参数?

注意:可选参数后面不允许出现必须参数。

function Sum(x: number, y?: number) {
  if (y) return x + y;
  return x;
}
​
let sum1 = Sum(1);
let sum2 = Sum(1, 0);

参数默认值

添加了参数默认值的TypeScript会识别为可选参数,且不受可选参数必须接在必须参数后面的限制。

function Sum(x: number, y: number = 0) {
  return x + y;
}

关于默认参数可参考【ES6中函数的参数默认值

剩余参数

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

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

重载

允许多个函数接受不同类型或数量的参数,作不同的处理。

  1. 联合类型

    function reverse (x: number | string): number | string | void {
      if (typeof x === 'number') 
          return Number(x.toString().split('').reverse().join(''));
      else if (typeof x === 'string') 
          return x.split('').reverse().join('');
    }
    

    但是不能准确表达输入为数字的时候,输出为数字;输入为字符串的时候,输出为字符串。

  2. 使用重载定义

    function reverse(x: number): number;
    function reverse(x: string): string;
    function reverse(x: number | string): number | string | void {
      // ...
    }
    ​
    // 重复多次定义 reverse,前几次为函数定义,最后一次为函数实现。
    // TypeScript会优先从最前面的函数开始匹配,所以多个函数定义如果有包含关系需要优先把精确的定义写在前面。