TypeScript极简入门
TypeScript 是 JavaScript 的超集,添加了静态类型系统和其他高级特性。本文面向已有 JavaScript 基础的开发者,快速介绍 TypeScript 的核心语法和常用特性。
# 一、TypeScript 简介
# 什么是 TypeScript
TypeScript 是由微软开发的开源编程语言,于 2012 年发布。它在 JavaScript 的基础上添加了:
- 静态类型系统:编译时类型检查,减少运行时错误
- 面向对象特性:接口、枚举、泛型、装饰器等
- 现代 JavaScript 特性:支持最新的 ES 标准
- 工具支持:强大的 IDE 智能提示和重构能力
TypeScript 与 JavaScript 的关系:
- TypeScript 是 JavaScript 的超集,所有 JavaScript 代码都是有效的 TypeScript 代码
- TypeScript 编译后生成纯 JavaScript,可在任何 JavaScript 环境中运行
- 如果你需要复习 JavaScript 基础,可以参考 JavaScript极简入门
# 为什么使用 TypeScript
- 类型安全:编译时发现错误,减少运行时 bug
- 更好的 IDE 支持:智能提示、自动补全、重构
- 可读性强:类型注解让代码自文档化
- 易于维护:大型项目中类型系统提供可靠的代码重构支持
- 渐进式采用:可以逐步将 JavaScript 项目迁移到 TypeScript
# 安装与配置
# 全局安装 TypeScript
npm install -g typescript
# 查看版本
tsc --version
# 初始化 TypeScript 项目
tsc --init
这会生成 tsconfig.json 配置文件:
{
"compilerOptions": {
"target": "ES2020", // 编译目标
"module": "commonjs", // 模块系统
"lib": ["ES2020"], // 包含的库
"outDir": "./dist", // 输出目录
"rootDir": "./src", // 源码目录
"strict": true, // 严格模式
"esModuleInterop": true, // ES 模块互操作
"skipLibCheck": true, // 跳过库文件检查
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
# Hello TypeScript
创建 hello.ts:
function greet(name: string): string {
return `Hello, ${name}!`;
}
const message = greet('TypeScript');
console.log(message);
编译并运行:
tsc hello.ts # 生成 hello.js
node hello.js # 运行
# 或使用 ts-node 直接运行
npm install -g ts-node
ts-node hello.ts
# 二、基础类型
# 基本类型
// 布尔值
let isDone: boolean = false;
// 数字
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
// 字符串
let color: string = "blue";
let fullName: string = `Bob Smith`;
let sentence: string = `Hello, my name is ${fullName}`;
// 数组
let list1: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3]; // 泛型写法
// 元组(固定长度和类型的数组)
let tuple: [string, number];
tuple = ['hello', 10]; // 正确
// tuple = [10, 'hello']; // 错误
// 枚举
enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green;
// any(任意类型,慎用)
let notSure: any = 4;
notSure = "maybe a string";
notSure = false;
// unknown(类型安全的 any)
let value: unknown = 4;
value = "string";
// let str: string = value; // 错误:需要类型断言
let str: string = value as string; // 正确
// void(无返回值)
function warnUser(): void {
console.log("Warning!");
}
// null 和 undefined
let u: undefined = undefined;
let n: null = null;
// never(永不返回)
function error(message: string): never {
throw new Error(message);
}
// object
let obj: object = { name: 'Alice' };
# 类型推断
TypeScript 可以自动推断类型:
let num = 5; // 推断为 number
let str = "hello"; // 推断为 string
let arr = [1, 2, 3]; // 推断为 number[]
// num = "error"; // 错误:不能将 string 赋值给 number
# 联合类型
变量可以是多种类型之一:
let value: string | number;
value = "hello"; // 正确
value = 42; // 正确
// value = true; // 错误
function printId(id: number | string) {
console.log(`Your ID is: ${id}`);
}
printId(101); // 正确
printId("202"); // 正确
# 类型别名
type ID = number | string;
function printId(id: ID) {
console.log(id);
}
// 复杂类型别名
type User = {
id: ID;
name: string;
age: number;
};
const user: User = {
id: 1,
name: 'Alice',
age: 30
};
# 字面量类型
let direction: "up" | "down" | "left" | "right";
direction = "up"; // 正确
// direction = "top"; // 错误
type Status = "pending" | "success" | "error";
let status: Status = "pending";
// 数字字面量
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
let roll: DiceRoll = 3;
# 三、接口(Interface)
# 对象类型
interface User {
id: number;
name: string;
email: string;
}
const user: User = {
id: 1,
name: 'Alice',
email: 'alice@example.com'
};
# 可选属性
interface User {
id: number;
name: string;
email?: string; // 可选属性
}
const user1: User = { id: 1, name: 'Alice' }; // 正确
const user2: User = { id: 2, name: 'Bob', email: 'bob@example.com' }; // 正确
# 只读属性
interface Point {
readonly x: number;
readonly y: number;
}
const p: Point = { x: 10, y: 20 };
// p.x = 5; // 错误:只读属性
# 函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
const mySearch: SearchFunc = function(src, sub) {
return src.indexOf(sub) > -1;
};
console.log(mySearch('hello world', 'world')); // true
# 可索引类型
interface StringArray {
[index: number]: string;
}
const myArray: StringArray = ["Bob", "Alice"];
const myStr: string = myArray[0];
// 字典类型
interface StringDictionary {
[key: string]: string;
}
const dict: StringDictionary = {
name: 'Alice',
city: 'Beijing'
};
# 继承接口
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
const square: Square = {
color: 'blue',
sideLength: 10
};
// 多重继承
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
# 四、函数
# 函数类型
// 函数声明
function add(x: number, y: number): number {
return x + y;
}
// 函数表达式
const multiply = function(x: number, y: number): number {
return x * y;
};
// 箭头函数
const subtract = (x: number, y: number): number => x - y;
// 完整函数类型
let myAdd: (x: number, y: number) => number = function(x, y) {
return x + y;
};
# 可选参数和默认参数
// 可选参数
function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return `${firstName} ${lastName}`;
}
return firstName;
}
console.log(buildName('Bob')); // 'Bob'
console.log(buildName('Bob', 'Smith')); // 'Bob Smith'
// 默认参数
function greet(name: string, greeting: string = 'Hello'): string {
return `${greeting}, ${name}!`;
}
console.log(greet('Alice')); // 'Hello, Alice!'
console.log(greet('Alice', 'Hi')); // 'Hi, Alice!'
# 剩余参数
function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
# 函数重载
function reverse(x: string): string;
function reverse(x: number): number;
function reverse(x: string | number): string | number {
if (typeof x === 'string') {
return x.split('').reverse().join('');
} else {
return Number(x.toString().split('').reverse().join(''));
}
}
console.log(reverse('hello')); // 'olleh'
console.log(reverse(12345)); // 54321
# 五、类(Class)
# 基本类
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): string {
return `Hello, I'm ${this.name}, ${this.age} years old.`;
}
}
const alice = new Person('Alice', 30);
console.log(alice.greet());
# 访问修饰符
class Person {
public name: string; // 公共(默认)
private age: number; // 私有
protected gender: string; // 受保护
constructor(name: string, age: number, gender: string) {
this.name = name;
this.age = age;
this.gender = gender;
}
getAge(): number {
return this.age; // 类内部可访问
}
}
const person = new Person('Alice', 30, 'female');
console.log(person.name); // 正确:public
// console.log(person.age); // 错误:private
console.log(person.getAge()); // 正确:通过方法访问
# 简写形式
class Person {
constructor(
public name: string,
private age: number,
protected gender: string
) {} // 自动创建并初始化属性
getAge(): number {
return this.age;
}
}
# 只读属性
class Person {
readonly id: number;
name: string;
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
}
const person = new Person(1, 'Alice');
// person.id = 2; // 错误:只读属性
# Getter 和 Setter
class Person {
private _age: number = 0;
get age(): number {
return this._age;
}
set age(value: number) {
if (value < 0) {
throw new Error('Age cannot be negative');
}
this._age = value;
}
}
const person = new Person();
person.age = 30; // 调用 setter
console.log(person.age); // 调用 getter
# 静态成员
class MathUtil {
static PI: number = 3.14159;
static circleArea(radius: number): number {
return this.PI * radius * radius;
}
}
console.log(MathUtil.PI); // 3.14159
console.log(MathUtil.circleArea(5)); // 78.53975
# 抽象类
abstract class Animal {
abstract makeSound(): void; // 抽象方法
move(): void {
console.log('Moving...');
}
}
class Dog extends Animal {
makeSound(): void {
console.log('Woof!');
}
}
const dog = new Dog();
dog.makeSound(); // 'Woof!'
dog.move(); // 'Moving...'
// const animal = new Animal(); // 错误:不能实例化抽象类
# 继承
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
move(distance: number = 0): void {
console.log(`${this.name} moved ${distance}m.`);
}
}
class Dog extends Animal {
constructor(name: string) {
super(name); // 调用父类构造函数
}
bark(): void {
console.log('Woof!');
}
move(distance: number = 5): void {
console.log('Running...');
super.move(distance); // 调用父类方法
}
}
const dog = new Dog('Rex');
dog.bark(); // 'Woof!'
dog.move(10); // 'Running...' 'Rex moved 10m.'
# 六、泛型(Generics)
# 泛型函数
// 不使用泛型
function identity(arg: number): number {
return arg;
}
// 使用泛型
function identity<T>(arg: T): T {
return arg;
}
const num = identity<number>(42);
const str = identity<string>('hello');
const bool = identity(true); // 类型推断
# 泛型数组
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length);
return arg;
}
loggingIdentity([1, 2, 3]);
loggingIdentity(['a', 'b', 'c']);
# 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T;
}
const myIdentity: GenericIdentityFn<number> = function(arg) {
return arg;
};
console.log(myIdentity(42));
# 泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
constructor(zeroValue: T, add: (x: T, y: T) => T) {
this.zeroValue = zeroValue;
this.add = add;
}
}
const myGenericNumber = new GenericNumber<number>(
0,
(x, y) => x + y
);
console.log(myGenericNumber.add(5, 3)); // 8
# 泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在可以访问 length
return arg;
}
loggingIdentity('hello'); // 正确:string 有 length
loggingIdentity([1, 2, 3]); // 正确:array 有 length
// loggingIdentity(3); // 错误:number 没有 length
# 多个类型参数
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const p1 = pair<number, string>(1, 'one');
const p2 = pair(2, 'two'); // 类型推断
# 七、枚举(Enum)
# 数字枚举
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
let dir: Direction = Direction.Up;
console.log(dir); // 0
// 指定起始值
enum Status {
Pending = 1,
Success, // 2
Error // 3
}
# 字符串枚举
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
console.log(Direction.Up); // "UP"
# 常量枚举
const enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green; // 编译后直接替换为数字
# 八、类型断言
# as 语法
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
# 尖括号语法
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;
注意:在 JSX 中只能使用 as 语法。
# 非空断言
function liveDangerously(x?: number | null) {
console.log(x!.toFixed()); // 断言 x 不为 null/undefined
}
liveDangerously(42); // 正确
// liveDangerously(null); // 运行时错误
# 九、类型守卫
# typeof 类型守卫
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // value 被推断为 string
} else {
console.log(value.toFixed(2)); // value 被推断为 number
}
}
# instanceof 类型守卫
class Dog {
bark() { console.log('Woof!'); }
}
class Cat {
meow() { console.log('Meow!'); }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark(); // animal 被推断为 Dog
} else {
animal.meow(); // animal 被推断为 Cat
}
}
# in 类型守卫
interface Fish {
swim: () => void;
}
interface Bird {
fly: () => void;
}
function move(animal: Fish | Bird) {
if ("swim" in animal) {
animal.swim(); // animal 被推断为 Fish
} else {
animal.fly(); // animal 被推断为 Bird
}
}
# 自定义类型守卫
interface Fish {
swim: () => void;
}
interface Bird {
fly: () => void;
}
function isFish(animal: Fish | Bird): animal is Fish {
return (animal as Fish).swim !== undefined;
}
function move(animal: Fish | Bird) {
if (isFish(animal)) {
animal.swim(); // animal 被推断为 Fish
} else {
animal.fly(); // animal 被推断为 Bird
}
}
# 十、工具类型
TypeScript 提供了多个内置工具类型:
# Partial(可选)
interface User {
id: number;
name: string;
email: string;
}
// 所有属性变为可选
type PartialUser = Partial<User>;
const user: PartialUser = {
name: 'Alice'
};
# Required(必需)
interface User {
id?: number;
name?: string;
}
// 所有属性变为必需
type RequiredUser = Required<User>;
const user: RequiredUser = {
id: 1,
name: 'Alice'
};
# Readonly(只读)
interface User {
id: number;
name: string;
}
// 所有属性变为只读
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = {
id: 1,
name: 'Alice'
};
// user.name = 'Bob'; // 错误:只读
# Pick(选取)
interface User {
id: number;
name: string;
email: string;
age: number;
}
// 选取部分属性
type UserPreview = Pick<User, 'id' | 'name'>;
const preview: UserPreview = {
id: 1,
name: 'Alice'
};
# Omit(排除)
interface User {
id: number;
name: string;
email: string;
password: string;
}
// 排除部分属性
type PublicUser = Omit<User, 'password'>;
const user: PublicUser = {
id: 1,
name: 'Alice',
email: 'alice@example.com'
};
# Record(记录)
type Role = 'admin' | 'user' | 'guest';
type Permissions = Record<Role, string[]>;
const permissions: Permissions = {
admin: ['read', 'write', 'delete'],
user: ['read', 'write'],
guest: ['read']
};
# 十一、模块
# 导出
// math.ts
export const PI = 3.14159;
export function add(x: number, y: number): number {
return x + y;
}
export class Calculator {
multiply(x: number, y: number): number {
return x * y;
}
}
// 默认导出
export default class MathUtil {
static square(x: number): number {
return x * x;
}
}
# 导入
// app.ts
import MathUtil, { PI, add, Calculator } from './math';
console.log(PI);
console.log(add(2, 3));
const calc = new Calculator();
console.log(calc.multiply(2, 3));
console.log(MathUtil.square(5));
// 重命名导入
import { add as sum } from './math';
// 导入所有
import * as math from './math';
console.log(math.PI);
# 十二、命名空间
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
export class EmailValidator implements StringValidator {
isValid(s: string): boolean {
return /\S+@\S+\.\S+/.test(s);
}
}
export class UrlValidator implements StringValidator {
isValid(s: string): boolean {
return /^https?:\/\//.test(s);
}
}
}
const emailValidator = new Validation.EmailValidator();
console.log(emailValidator.isValid('test@example.com')); // true
注意:在现代 TypeScript 项目中,推荐使用 ES6 模块而非命名空间。
# 十三、配置与编译
# tsconfig.json 常用选项
{
"compilerOptions": {
/* 基本选项 */
"target": "ES2020", // 编译目标版本
"module": "commonjs", // 模块系统
"lib": ["ES2020", "DOM"], // 包含的库
"outDir": "./dist", // 输出目录
"rootDir": "./src", // 源码目录
/* 严格模式 */
"strict": true, // 启用所有严格类型检查
"noImplicitAny": true, // 禁止隐式 any
"strictNullChecks": true, // 严格的 null 检查
"strictFunctionTypes": true, // 严格的函数类型检查
"noUnusedLocals": true, // 未使用的局部变量报错
"noUnusedParameters": true, // 未使用的参数报错
/* 模块解析 */
"moduleResolution": "node", // 模块解析策略
"baseUrl": "./", // 基础路径
"paths": { // 路径映射
"@/*": ["src/*"]
},
"esModuleInterop": true, // ES 模块互操作
/* 其他 */
"skipLibCheck": true, // 跳过库文件类型检查
"forceConsistentCasingInFileNames": true,
"declaration": true, // 生成 .d.ts 声明文件
"sourceMap": true, // 生成 source map
"removeComments": true // 移除注释
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
# 编译命令
# 编译单个文件
tsc hello.ts
# 编译项目(使用 tsconfig.json)
tsc
# 监听模式
tsc --watch
# 指定配置文件
tsc --project tsconfig.prod.json
# 十四、实用技巧
# 类型推断技巧
// 从函数返回值推断
function createUser() {
return {
id: 1,
name: 'Alice',
email: 'alice@example.com'
};
}
type User = ReturnType<typeof createUser>;
// User 类型为 { id: number; name: string; email: string; }
# 常量断言
// 普通对象
const config = {
host: 'localhost',
port: 3000
};
// config 类型:{ host: string; port: number; }
// 使用 const 断言
const config = {
host: 'localhost',
port: 3000
} as const;
// config 类型:{ readonly host: "localhost"; readonly port: 3000; }
// 数组
const colors = ['red', 'green', 'blue'] as const;
// colors 类型:readonly ["red", "green", "blue"]
# 索引签名
interface Dictionary {
[key: string]: string | number;
}
const dict: Dictionary = {
name: 'Alice',
age: 30,
city: 'Beijing'
};
# 映射类型
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
// { readonly id: number; readonly name: string; }
# 十五、总结
TypeScript 通过静态类型系统为 JavaScript 添加了强大的类型安全保障:
- 基础类型:基本类型、联合类型、字面量类型
- 接口:对象类型、可选属性、只读属性、继承
- 函数:类型注解、重载、泛型
- 类:访问修饰符、继承、抽象类
- 泛型:函数、类、接口、约束
- 枚举:数字枚举、字符串枚举
- 类型守卫:typeof、instanceof、in、自定义
- 工具类型:Partial、Required、Pick、Omit、Record
- 模块:导入导出、命名空间
掌握这些核心概念后,你可以编写类型安全、易于维护的 TypeScript 代码。更多高级特性(如条件类型、infer 关键字、装饰器等),详见 TypeScript高级特性详解。
祝你变得更强!
编辑 (opens new window)
上次更新: 2025/11/07