TypeScript 库开发教程
1. TypeScript 简介和优势
TypeScript 是 JavaScript 的超集,它添加了静态类型和其他现代编程语言的特性。TypeScript 的主要优势包括:
- 静态类型检查:在编译时捕获错误,减少运行时错误。
- 更好的代码可读性和维护性:类型注解使得代码更易于理解和维护。
- 强大的工具支持:IDE 可以提供更好的自动补全、重构和导航功能。
- 现代语言特性:支持 ES6+ 特性,如类、模块、箭头函数等。
2. 开发环境搭建
2.1 安装 Node.js
首先,确保你已经安装了 Node.js。你可以从 Node.js 官网 下载并安装。
2.2 安装 TypeScript 编译器
使用 npm 安装 TypeScript 编译器:
npm install -g typescript
2.3 创建项目目录
创建一个新的项目目录并初始化 npm:
mkdir my-typescript-library
cd my-typescript-library
npm init -y
2.4 初始化 TypeScript 项目
在项目根目录下运行以下命令来初始化 TypeScript 项目:
tsc --init
这将生成一个 tsconfig.json 文件,用于配置 TypeScript 编译器。
3. 第一个 TypeScript 程序
创建一个 src 目录,并在其中创建一个 index.ts 文件:
// src/index.ts
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("TypeScript"));
编译并运行这个程序:
tsc
node dist/index.js
你应该会看到输出:
Hello, TypeScript!
4. 基本类型和变量声明
TypeScript 支持多种基本类型:
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10];
5. TypeScript 配置文件 (tsconfig.json)
tsconfig.json 文件用于配置 TypeScript 编译器的行为。以下是一个简单的配置示例:
{
"compilerOptions": {
"target": "ES6",
"module": "CommonJS",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
6. 基本类型详解
6.1 Number
TypeScript 中的 number 类型用于表示数字,包括整数和浮点数:
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
6.2 String
string 类型用于表示文本数据:
let color: string = "blue";
color = 'red';
6.3 Boolean
boolean 类型用于表示真或假:
let isDone: boolean = false;
6.4 Array
数组类型可以定义为特定类型的数组:
let list: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3];
6.5 Tuple
元组类型允许表示一个已知元素数量和类型的数组:
let x: [string, number];
x = ["hello", 10];
7. 枚举类型
枚举类型用于定义一组命名常量:
enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green;
8. Any 和 Unknown 类型
any 类型允许变量存储任何类型的值:
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;
unknown 类型类似于 any,但在类型检查时更安全:
let notSure: unknown = 4;
notSure = "maybe a string instead";
notSure = false;
9. Void, Null 和 Undefined
void 类型表示没有任何类型:
function warnUser(): void {
console.log("This is my warning message");
}
null 和 undefined 是所有类型的子类型:
let u: undefined = undefined;
let n: null = null;
10. Never 类型
never 类型表示永不存在的值的类型:
function error(message: string): never {
throw new Error(message);
}
11. 类型断言
类型断言允许你告诉编译器某个值的具体类型:
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
12. 函数声明和表达式
函数声明:
function add(x: number, y: number): number {
return x + y;
}
函数表达式:
let myAdd = function(x: number, y: number): number {
return x + y;
};
13. 可选参数和默认参数
可选参数:
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + " " + lastName;
} else {
return firstName;
}
}
默认参数:
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
14. 剩余参数
剩余参数允许函数接受不定数量的参数:
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
15. 函数重载
函数重载允许定义多个函数签名:
function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: any, b: any): any {
return a + b;
}
16. This 和箭头函数
箭头函数不会改变 this 的上下文:
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
17. 接口定义和使用
接口用于定义对象的形状:
interface LabeledValue {
label: string;
}
function printLabel(labeledObj: LabeledValue) {
console.log(labeledObj.label);
}
18. 可选属性和只读属性
可选属性:
interface SquareConfig {
color?: string;
width?: number;
}
只读属性:
interface Point {
readonly x: number;
readonly y: number;
}
19. 函数类型接口
接口可以描述函数类型:
interface SearchFunc {
(source: string, subString: string): boolean;
}
20. 类类型接口
接口可以描述类的结构:
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
class Clock implements ClockInterface {
currentTime: Date = new Date();
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) {}
}
21. 继承接口
接口可以继承其他接口:
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
22. 类型别名 vs 接口
类型别名可以用于定义复杂类型:
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
23. 类的定义和实例化
定义类:
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
实例化类:
let greeter = new Greeter("world");
24. 继承和多态
继承:
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
多态:
let dog = new Dog();
dog.bark();
dog.move(10);
25. 访问修饰符 (public, private, protected)
public 是默认的访问修饰符:
class Animal {
public name: string;
public constructor(theName: string) { this.name = theName; }
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
private 修饰符限制访问:
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
protected 修饰符允许子类访问:
class Person {
protected name: string;
constructor(name: string) { this.name = name; }
}
class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}
26. 静态属性和方法
静态属性和方法属于类本身:
class Grid {
static origin = {x: 0, y: 0};
calculateDistanceFromOrigin(point: {x: number; y: number;}) {
let xDist = (point.x - Grid.origin.x);
let yDist = (point.y - Grid.origin.y);
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
}
constructor (public scale: number) { }
}
27. 抽象类
抽象类不能直接实例化,只能被继承:
abstract class Department {
constructor(public name: string) {}
printName(): void {
console.log("Department name: " + this.name);
}
abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
constructor() {
super("Accounting and Auditing"); // 在派生类的构造函数中必须调用 super()
}
printMeeting(): void {
console.log("The Accounting Department meets each Monday at 10am.");
}
generateReports(): void {
console.log("Generating accounting reports...");
}
}
28. 交叉类型
交叉类型将多个类型合并为一个类型:
function extend<T, U>(first: T, second: U): T & U {
let result = <T & U>{};
for (let id in first) {
(<any>result)[id] = (<any>first)[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
(<any>result)[id] = (<any>second)[id];
}
}
return result;
}
29. 联合类型
联合类型允许变量具有多种类型之一:
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
30. 类型保护和类型区分
类型保护用于在运行时检查变量的类型:
function isFish(pet: Fish | Bird): pet is Fish {
return (<Fish>pet).swim !== undefined;
}
31. 可为 null 的类型
TypeScript 支持可为 null 的类型:
let s = "foo";
s = null; // 错误, 'null' 不能赋值给 'string'
let sn: string | null = "bar";
sn = null; // 正确
32. 字面量类型
字面量类型允许你指定变量的具体值:
let x: "hello" = "hello";
x = "hello"; // 正确
x = "howdy"; // 错误
33. 索引类型和映射类型
索引类型允许你查询对象的属性类型:
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map(n => o[n]);
}
映射类型允许你创建新的类型:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
34. 泛型函数
泛型函数允许你编写可以处理多种类型的函数:
function identity<T>(arg: T): T {
return arg;
}
35. 泛型接口
泛型接口允许你定义可以处理多种类型的接口:
interface GenericIdentityFn<T> {
(arg: T): T;
}
36. 泛型类
泛型类允许你定义可以处理多种类型的类:
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
37. 泛型约束
泛型约束允许你限制泛型参数的类型:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在我们知道它有 .length 属性,所以不会报错
return arg;
}
38. ES6 模块系统
ES6 模块系统允许你将代码组织为模块:
// math.ts
export function add(x: number, y: number): number {
return x + y;
}
// app.ts
import { add } from './math';
console.log(add(1, 2)); // 输出 3
39. 命名空间
命名空间用于组织代码:
namespace Validation {
export interface StringValidator