# 2. 基础类型
ts常用类型及基本概念
# 基本数据类型
js 类型分两种,基本数据类型(primitive data types)和对象类型(object types), 这里除了介绍js的5中基本数据类型外,还将介绍ts新增的void, any 等 , (js新增的两种基本类型 symbol (ES2015), bigint (ES2019) 这里暂不介绍)
# boolean
let isOk: boolean = false
let createdBoolean: boolean = new Boolean(1) // Error
// typeof new Boolean(1) is 'object'
// typeof Boolean(false) is 'boolean'
// 类似的可以new的还有 String, Number
// Symbol、BigInt 没有new 构造函数
# number
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// ES6 中的二进制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
// 编译后,不同的是 二进制、八进制 会被编译为10进制
// let 也会转为 var
var decLiteral = 6;
var hexLiteral = 0xf00d;
// ES6 中的二进制表示法
var binaryLiteral = 10;
// ES6 中的八进制表示法
var octalLiteral = 484;
var notANumber = NaN;
var infinityNumber = Infinity;
# string
let name: string = 'Tom'
let str: string = `Hello, ${name}`
// tsc 编译后
var namestr = 'Tom';
var str = "Hello, " + namestr;
# null 与 undefined
默认情况下,null 和 undefined是所有类型的子类型,也就是可以将null或undefined赋值给number、string等类型的变量
let u: undefined = undefined
let n: null = null
let num2: string = null
// 转换后
var u = undefined
var n = null
var num2 = null
然而,当你指定了--strictNullChecks标记,null和undefined只能赋值给void和它们各自。 这能避免很多常见的问题。 也许在某处你想传入一个string或null或undefined,你可以使用联合类型string | null | undefined。 再次说明,稍后我们会介绍联合类型。 注意:我们鼓励尽可能地使用--strictNullChecks,但在本手册里我们假设这个标记是关闭的。
# 数组: Array<类型> 或 类型[]
ts有两种方式定义数组:
# 元素类型后面接上[]
let list: number[] = [1, 2, 3]
// var list = [1, 2, 3];
# 使用数组泛型
uses a generic array type,
Array<elemType>
泛型(Generic)所操作的数据类型被指定为一个参数
let list2: Array<number> = [1, 2, 3]
// var list2 = [1, 2, 3];
# 元组 tuple
tuple,也是一个数组,且已知数组长度,以及每个元素的类型,每个元素类型可以不一致
// Declare a tuple type 声明一个元组类型
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly 错误的初始化
x = [10, 'hello']; // Error
// 当访问越界的元素,会使用联合类型代替(后面后讲到)
x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型
console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString
x[6] = true; // Error, 布尔不是(string | number)类型
# 枚举 enum
枚举类型可以为一组数值赋予友好的名字
enum Color {Red, Green, Blue} // 默认从0开始为元素编号
let c: Color = Color.Green; // 获取该枚举的索引值
let colorName: string = Color[2]; // 获取枚举字符串
console.log(c, colorName) // 1 'Blue'
// 编译为
var Color;
(function (Color) {
Color[Color["Red"] = 0] = "Red";
Color[Color["Green"] = 1] = "Green";
Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {})); // 默认从0开始为元素编号
var c = Color.Green;
var colorName = Color[2];
console.log(c, colorName);
// 可以改变开始索引
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;
// 也可以全部索引手动赋值
enum Color { Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green
# any 任意值
let notSure: any = 4
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
// 数组元素类型为any
let list: any[] = [1, true, "free"];
list[1] = 100;
# void 空值
与any类型相反,它表示没有任何类型。一般用于没有任何返回值的函数,void类型只能赋值为 null 或undefined,不能将void类型的值赋值给 number 等
function alertName(): void {
alert('My name is Tom')
}
// 单独声明一个void类型没有什么用处,只能赋值为 undefined或null
let unusable: void = undefined
unusable = null; // OK if `--strictNullChecks` is not given
let u: void = undefined
let num: number = u // Error
# never
never类型
- 总是会抛出异常
- 根本就不会有返回值的函数表达式
- 箭头函数表达式的返回值类型
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
# object
object表示非原始类型,也就是除number,string,boolean,symbol,bigint, null或undefined之外的类型。
使用object类型,就可以更好的表示像Object.create这样的API。例如:
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error
# 类型断言(Type assertions)
通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。
一句话解释:手动指定一个值的类型。
Type assertions have two forms. 当在TypeScript里使用JSX时,只有as语法断言是被允许的。
# “angle-bracket” syntax ('尖括号'语法)
let someValue: any = 'this is a string'
let strLength: number = (<string>someValue).length
# as syntax(as语法)
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
# 关于let
不推荐使用var, 很多常见的问题都可以通过使用let来解决, 尽可能地使用let来代替var
ts官网用了一个章节(变量声明)来讲let和var,这些是js基础,所以这里不讨论,可以参考: TypeScript - Variable Declarations (opens new window)
# 类型推论
声明变量时如果没有指定类型,那ts会依照类型推论(Type Inference)的规则来推断出一个类型,如果声明时没有赋值,不管之后有没有赋值,都会被推断为 any类型
let testNumber = 'six' // 这里会根据值的类型,推断出testNumber为string
testNumber = 6 // Error
// 声明时不赋值
let testNumber; // 等价于 let testNumber: any
testNumber = 'six'
testNumber = 6
# 联合类型(Union Types)
联合类型,表示值可以为多种类型中的一种,以 | 分隔
let myNumber: string | number
myNumber = 'six'
myNumber = 6
# 访问联合类型的属性和方法
当不确定联合类型到底是哪个类型时,只能访问此联合类型的所有类型里共有的属性或方法
function fun(myNumber: string | number): number {
console.log(myNumber.length) // Error
console.log(myNumber.toString()) // OK
}
# 联合类型的变量赋值时类型推断
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
let myNumber = myNumber: string | number
myNumber = 'six' // myNumber被推断为 string 类型
console.log(myNumber.length) // OK
myNumber = 6 // myNumber被推断为 number 类型
console.log(myNumber.length) // Error