基础类型
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