一、TypeScript 是什么?
JavaScript 是一种动态类型语言,变量的类型在运行时才确定。这种特性虽然提供了灵活性,但也导致了许多可以在编译阶段避免的错误无法提前发现。TypeScript 为 JavaScript 提供了一套静态类型系统,能够在编译阶段进行强类型检查。通过 TypeScript,我们可以在编译时发现大部分错误,同时借助编辑器和 IDE 提供的代码补全、接口提示、跳转到定义和重构等功能,提升开发效率并减少 bug 的出现。TypeScript 建立在 JavaScript 的基础之上,现有的 .js 文件可以直接重命名为 .ts 文件即可。
二、基本的类型注解
在 JavaScript 中,变量声明通常使用 var、let 或 const,但不关心变量的类型。而在 TypeScript 中,可以在声明变量时明确指定其类型,这不仅有助于类型检查,还能起到注释说明的作用。
1. 原始类型
JavaScript 的原始类型(如 string、number、boolean)在 TypeScript 中可以直接用作类型注解:
let num: number;
let str: string;
let bool: boolean;
num = 123; // 正确
num = '123'; // 错误
str = '123'; // 正确
str = 123; // 错误
bool = true; // 正确
bool = 'false'; // 错误
2. 特殊类型
TypeScript 提供了一些特殊类型,包括 void、null、undefined 和 any。
(1)void
void 表示一个函数没有返回值:
function log(message: string): void {
console.log(message);
}
(2)null 和 undefined
在默认情况下(strictNullChecks: false),null 和 undefined 可以被赋值给任意类型:
let num: number;
let str: string;
num = null; // 正确
str = undefined; // 正确
(3)any
any 类型允许变量接受任意类型值,并关闭类型检查:
let power: any;
power = '123'; // 正确
power = 123; // 正确
let num: number;
power = num; // 正确
num = power; // 正确
注意:尽量避免使用 any,以确保类型安全。
3. 数组
TypeScript 使用后缀 [] 来定义数组类型:
let boolArray: boolean[];
boolArray = [true, false]; // 正确
boolArray[0] = 'false'; // 错误
4. 元组
元组用于表示固定长度和类型的数组:
let nameNumber: [string, number];
nameNumber = ['Jenny', 221345]; // 正确
nameNumber = ['Jenny', '221345']; // 错误
5. 枚举
枚举用于定义一组命名常量:
enum Gender { Male, Female }
let gender = Gender.Male;
注意:枚举在编译后仍然存在于 JavaScript 文件中。
6. 联合类型
联合类型使用 | 表示一个值可以是多种类型之一:
function formatCommandline(command: string[] | string) {
let line = '';
if (typeof command === 'string') {
line = command.trim();
} else {
line = command.join(' ').trim();
}
}
7. 交叉类型
交叉类型使用 & 将多个类型合并为一个类型:
function extend<T, U>(first: T, second: U): T & U {
const result = <T & U>{};
for (let id in first) {
(<T>result)[id] = first[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
(<U>result)[id] = second[id];
}
}
return result;
}
const x = extend({ a: 'hello' }, { b: 42 });
三、函数类型
1. 参数注解
可以为函数参数指定类型:
function add(x: number, y: number): number {
return x + y;
}
let myAdd = function(x: number, y: number): number { return x + y; };
2. 可选参数
使用 ? 标记参数为可选:
function add(x: number, y?: number): number {
return x + y;
}
注意:可选参数必须位于必填参数之后。
3. 类型推断
TypeScript 通常可以自动推断函数返回值的类型。
4. 类型别名
使用 type 为复杂类型创建别名:
type StrOrNum = string | number;
let sample: StrOrNum;
sample = 123; // 正确
sample = '123'; // 正确
sample = true; // 错误
5. 接口
接口用于定义对象的结构:
interface Name {
first: string;
second: string;
}
let name: Name;
name = {
first: 'John',
second: 'Doe'
}; // 正确
6. 内联类型注解
可以直接使用内联注解定义类型:
let name: {
first: string;
second: string;
};
name = {
first: 'John',
second: 'Doe'
}; // 正确
四、泛型
泛型用于定义不依赖具体类型的函数或数据结构:
function reverse<T>(items: T[]): T[] {
const toreturn: T[] = [];
for (let i = items.length - 1; i >= 0; i--) {
toreturn.push(items[i]);
}
return toreturn;
}
const sample = [1, 2, 3];
let reversed = reverse(sample);
reversed[0] = '1'; // 错误
reversed = [1, 2]; // 正确
本章内容摘选自《深入理解 TypeScript》