基础类型

TypeScript 中的基础类型

TypeScript 为我们提供了 number, string, boolean, 等原始类型。

Number

跟 JavaScript 一样,TypeScript 所有的数都是浮点数类型,使用 number 关键字描述:

let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;

如果我们在代码中希望显式区分 int, float 等具体的数值类型,那么可以使用 type 来建立别名:

type int = number;

type float = number;

布尔类型的值使用 boolean 关键字描述,包含 true/false 两个值:

let isDone: boolean = false;

所有的字符串类型使用 string 关键字描述,包括双引号、单引号以及模板字符串方式声明的字符串对象:

let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}.

I'll be ${age + 1} years old next month.`;

值得一提的是,就像 Java 中 Long 与 long 的区别,TypeScript 会将 Number, String, Boolean 当做包含特定属性与方法的 Object 类型进行处理,我们应该尽量避免使用复合类似以避免意外地操作:

/* WRONG */
function reverse(s: String): String;

/* OK */
function reverse(s: string): string;

Enum | 枚举类型

类似于 Java 或者 C# 语言中的枚举类型,我们能够使用 enum 关键字来创建预定义好的常量集合:

enum StoryType {
  Video,
  Article,
  Tutorial
}
let st: StoryType = StoryType.Article;

值得一提的是,枚举类型被转化为 ES5 代码后,会使用数字来内置表示:

const StoryType;
(function(StoryType) {
  StoryType[(StoryType['Video'] = 0)] = 'Video';
  StoryType[(StoryType['Article'] = 1)] = 'Article';
  StoryType[(StoryType['Tutorial'] = 2)] = 'Tutorial';
})(StoryType || (StoryType = {}));
const st = StoryType.Article;

我们同样可以指定枚举值对应的数值:

enum StoryType {Video = 10, Article = 20, Tutorial=30}

从 Typescript 2.4 开始,支持了枚举类型使用字符串做为 value:

enum Colors {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}

Arrays & Tuple | 数组与元组

在 TypeScript 中,我们能够创建 Typed Arrays 或者 Generic Arrays,Typed Arrays 的创建方式如下:

const tags: string[] = ["javascript", "programming"];
tags.push("typescript");
tags.forEach(function(tag) {
  console.log(`Tag ${tag}`);
});

Generic Arrays 的创建方式如下:

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

我们也可以通过 interface 关键字来自定义数组类型:

interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

多维数组

多维数组的声明与初始化方式如下:

class Something {
  private things: Thing[][];

  constructor() {
    things = [];

    for (const i: number = 0; i < 10; i++) {
      this.things[i] = [];
      for (const j: number = 0; j < 10; j++) {
        this.things[i][j] = new Thing();
      }
    }
  }
}

从 2.7 版本开始,我们可以更精确的描述每一项的类型与数组总长度:

interface Data extends Array<number> {
  0: number;
  1: number;
  length: 2;
}

在很多情况下我们也需要去定义递归数组:

type Atom = string | boolean | number;

interface NestedArray extends Array<NestedArray | Atom> {  }

type AtomOrArray = Atom | NestedArray;

// Usage
let foo: AtomOrArray = ["", 1, [1, 2, ""] ]     let bar: AtomOrArray =  ""

Tuple

TypeScript 同时提供了 Tuple 元组类型,允许返回包含不同的已知类型的数组:

let storyTitles = [
  "Learning TypeScript",
  "Getting started with TypeScript",
  "Building your first app with TypeScript"
];

let titlesAndLengths: [string, number][] = storyTitles.map(function(title) {
  let tuple: [string, number] = [title, title.length];
  return tuple;
});

元组类型也可以通过 interface 接口方式声明:

interface KeyValuePair extends Array<number | string> {
  0: string;
  1: number;
}

空类型/未知类型

TypeScript 提供了 null, undefined, never, void 这几种空类型,它们都是其他类型的子类型,因为任何有类型的值都有可能是空(也就是执行期间可能没有值)。

Never

nerver 用于处理函数的异常流程,譬如永远不会返回值或者抛出异常。void 表示没有任何类型,never 表示永远不存在的值的类型。当一个函数没有返回值时,它返回了一个 void 类型,但是,当一个函数根本就没有返回值时(或者总是抛出错误),它返回了一个 never,void 指可以被赋值的类型(在 strictNullChecking 为 false 时),但是 never 不能赋值给其他任何类型,除了 never。

function fail(message: string): never {
  throw new Error(message);
}

never 类型的典型应用场景,就是处理函数中可能的不可达代码,譬如在调用上述的 fail 函数时,若其为非 never 类型,则会抛出不是所有的代码路径都返回值的异常:

function foo(x: string | number): boolean {
  if (typeof x === "string") {
    return true;
  } else if (typeof x === "number") {
    return false;
  }

  return fail("Unexhaustive!");
}

TypeScript 3.0 引入了一种名为 unknown 的新类型。与 any 一样,可以把任意值赋给 unknown。不过,与 any 不同的是,如果没有使用类型断言,则几乎没有可赋的值。你也不能访问 unknown 的任何属性,或者调用 / 构建它们。

let foo: unknown = 10;

// 因为 `foo` 是 `unknown` 类型, 所以这些地方会出错。
foo.y.prop;
foo.z.prop;
foo();
new foo();
upperCase(foo);
foo`hello world!`;

function upperCase(x: string) {
  return x.toUpperCase();
}

这个时候,我们可以执行强制检查,或者使用类型断言。

let foo: unknown = 10;

function hasXYZ(obj: any): obj is { x: any; y: any; z: any } {
  return (
    !!obj && typeof obj === "object" && "x" in obj && "y" in obj && "z" in obj
  );
}

// 使用用户定义的类型检查...
if (hasXYZ(foo)) {
  // ... 现在可以访问它的属性。
  foo.x.prop;
  foo.y.prop;
  foo.z.prop;
}

// 通过使用类型断言,我们告诉 TypeScript,我们知道自己在做什么。
upperCase(foo as string);

function upperCase(x: string) {
  return x.toUpperCase();
}

any

TypeScript 允许我们使用 any 关键字来描述不确定的类型,编译器会自动忽略对该类型的校验:

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
上一页
下一页