JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。
原始数据类型包括:数值、字符串、布尔值、null、undefined 以及 ES6 中的新类型 Symbol 和 BigInt。
数值 - Number
和JavaScript一样,TypeScript里的所有数字都是浮点数。 除了支持十进制和十六进制字面量,TypeScript还支持ES6中引入的二进制和八进制字面量。
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010; // 二进制
let octalLiteral: number = 0o744; // 八进制
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
编译后:
var decLiteral = 6;
var hexLiteral = 0xf00d;
var binaryLiteral = 10; // 二进制
var octalLiteral = 484; // 八进制
var notANumber = NaN;
var infinityNumber = Infinity;
ES6中的二进制和八进制编译后转为十进制。
字符串 - String
使用 string 定义字符串类型:
let myName: string = 'www';
let myAge: number = 18;
// 模板字符串
let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`;
编译后:
var myName = 'www';
var myAge = 18;
// 模板字符串
var sentence = "Hello, my name is " + myName + ".
I'll be " + (myAge + 1) + " years old next month.";
布尔值 - Boolean
最基本的数据类型就是简单的true/false值,在JavaScript和TypeScript里叫做boolean。
let isDone: boolean = false;
new Boolean() 返回的是一个 Boolean 对象:
let createdByNewBoolean: Boolean = new Boolean(1);
直接调用 Boolean 也可以返回一个 boolean 类型:
let createdByBoolean: boolean = Boolean(1);
在 TypeScript 中,boolean 是 JavaScript 中的基本类型,而 Boolean 是 JavaScript 中的构造函数。
空值 - Void
某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void:
function warnUser(): void {
console.log("This is my warning message");
}
声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:
let unusable: void = undefined;
Null 和 Undefined
TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。 和 void相似,它们的本身的类型用处不是很大:
let u: undefined = undefined;
let n: null = null;
默认情况下null和undefined是所有类型的子类型。 就是说你可以把 null和undefined赋值给number类型的变量。
let num: number = undefined;
而 void 类型的变量不能赋值给 number 类型的变量:
let u: void;
let num: number = u;
// Type 'void' is not assignable to type 'number'.
Never
never类型表示的是那些永不存在的值的类型。例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。
never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使 any也不可以赋值给never。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
元组 - Tuple
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
比如,定义一对值分别为 string 和 number 的元组:
let x: [string, number];
x = ['1', 1] // OK
x = [1, 1] // Error
x = ['1', 1, 2] // Error
当赋值或访问一个已知索引的元素时,会得到正确的类型:
console.log(x[0].substr(1)); // OK
console.log(x[1].substr(1)); // Error, 'number' does not have 'substr'
当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:
x.push(1); // OK
x.push('123'); // OK
x.push(true); // Error
枚举 - Enum
枚举(Enum)类型用于取值被限定在一定范围内的场景。比如,上下左右四个方向,一周七天,一年十二个月中取值。
枚举使用 enum 关键字来定义,枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 0); // true
console.log(Days[0] === "Sun"); // 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 = {}));
手动赋值
我们也可以给枚举项手动赋值:
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
上面的例子中,未手动赋值的枚举项会接着上一个枚举项递增。
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
数字枚举
常数枚举是使用 const enum 定义的枚举类型:
enum Directions {
Up = 1,
Down,
Left,
Right
}
const dir = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
var dir = [1, 2, 3, 4]; // 编译后
假如包含了计算成员,则会在编译阶段报错:
const enum Color {Red, Green, Blue = "blue".length};
// index.ts(1,38): error TS2474: In 'const' enum declarations member initializer must be constant expression.
Any
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这个时候可以定义为Any类型。任意值(Any)用来表示允许赋值为任意类型。
如果是一个普通类型,在赋值过程中改变类型是不被允许的:
let myValue: string = 'wwx';
myValue = 30;
// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
但如果是 any 类型,则允许被赋值为任意类型。
let myValue: any = 'wwx';
myValue = 30;
变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:
let something;
something = 'wwx';
something = 30;
something.setName('Tom');
等价于:
let something: any;
something = 'wwx';
something = 30;
something.setName('Tom');
当你只知道一部分数据的类型时,any类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:
let list: any[] = [1, true, "free"];
list[1] = 100;
任意值的属性和方法
在任意值上访问任何属性都是允许的:
let anyThing: any = 'hello'
console.log(anyThing.myName)
console.log(anyThing.myName.firstName);
也允许调用任何方法:
let anyThing2: any = 'Tom';
anyThing2.setName('Jerry');
anyThing2.setName('Jerry').sayHello();
anyThing2.myName.setFirstName('Cat');
上边这块编写的过程中不会报错,ts编译也会正常通过,并不代表运行不会报错。
联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种。
let value: string | number;
value = 'wwx'
value = 123;
访问联合类型的属性或方法
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:
function getLength(something: string | number): number {
return something.length;
}
// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
上例中,length 不是 string 和 number 的共有属性,所以会报错。
访问 string 和 number 的共有属性是没问题的:
function getString(something: string | number): string {
return something.toString();
}
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:
let value: string | number;
value = 'wwx';
console.log(value.length); // 3
value = 10;
console.log(myFavoriteNumber.length); // 编译时报错
// Property 'length' does not exist on type 'number'.
第二行value被推断为字符串,所以有length属性。第四行被推断为数字,没有length属性,所以报错。
参考
TypeScript 入门教程 - ts.xcatliu.com/
TypeScript 官网 - www.typescriptlang.org/