本文详细介绍了TypeScript的基础概念与语法,包括变量声明、函数定义、类和接口等,并深入探讨了TypeScript的高级特性如泛型和装饰器。此外,文章还提供了TypeScript大厂面试真题解析和实战项目案例,帮助读者更好地理解和应用TypeScript。
TypeScript 是由微软开发并维护的一种开源编程语言,它是 JavaScript 的一个超集,也就是说,所有的 JavaScript 代码都是有效的 TypeScript 代码,但是 TypeScript 引入了静态类型检查和一些面向对象的特性,使其更适合大型项目的开发。TypeScript 编译后的代码是标准的 JavaScript,可以在任何支持 JavaScript 的环境中运行。
TypeScript 的主要特性包括:
为了开始使用 TypeScript,你需要安装并配置 TypeScript 编译器。以下是详细的步骤:
最简单的方式是使用 npm(Node Package Manager)安装 TypeScript。打开命令行工具(如 PowerShell 或命令提示符),运行以下命令:
npm install -g typescript
这将全局安装 TypeScript 编译器。安装完成后,可以通过命令 tsc -v
来验证安装版本:
tsc -v
在你的项目根目录中创建一个 tsconfig.json
文件,它包含了编译器选项和其他配置。下面是一个基本的配置示例:
{ "compilerOptions": { "target": "es6", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "outDir": "./dist" }, "include": ["src/**/*"] }
target
:指定生成 JavaScript 的版本。module
:指定模块系统。strict
:启用所有严格类型检查。esModuleInterop
:允许从 ES 模块中导入默认导出。skipLibCheck
:跳过对库文件的类型检查。forceConsistentCasingInFileNames
:强制文件名一直使用相同大小写。outDir
:指定输出目录。include
:指定文件包含模式。在项目的 src
目录下创建一个文件 hello.ts
:
function sayHello(name: string) { return `Hello, ${name}`; } console.log(sayHello("TypeScript"));
使用 tsc
命令编译文件:
tsc
这将会在 dist
目录下生成编译后的 JavaScript 文件 hello.js
。
TypeScript 中提供了多种基本类型来定义变量。常见的基本类型包括:number
、string
、boolean
、null
、undefined
、void
、never
、any
和 unknown
。下面是一些示例代码:
let age: number = 25; let name: string = "TypeScript"; let isStudent: boolean = true; let nullValue: null = null; let undefinedValue: undefined = undefined; let voidValue: void = undefined; let neverValue: never = (() => { throw new Error(); })(); let anyValue: any = "Any type"; let unknownValue: unknown = "Unknown type";
使用 :
来定义变量的类型。例如:
let age: number = 25;
当你声明一个变量但没有明确指定其类型时,TypeScript 会根据其初始值进行类型推断。例如:
let name = "TypeScript"; // 类型推断为 string
定义一个函数时,可以指定函数的参数类型和返回类型。例如:
function add(a: number, b: number): number { return a + b; } let sum = add(3, 4); console.log(sum); // 输出 7
函数也可以作为表达式存在:
let calculate = function (x: number, y: number): number { return x * y; }; console.log(calculate(3, 4)); // 输出 12
可选参数和默认参数可以增强函数的灵活性:
function greet(name: string, message?: string) { message = message || "Hello"; console.log(`${message}, ${name}`); } greet("TypeScript"); // 输出 "Hello, TypeScript" greet("TypeScript", "Greetings"); // 输出 "Greetings, TypeScript"
类用于定义对象的行为和属性。类中可以包含构造函数、方法、属性和静态成员。
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } greet() { console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); } } let person = new Person("TypeScript", 25); person.greet(); // 输出 "Hello, my name is TypeScript and I am 25 years old."
接口用于定义对象的结构。可以用来实现类型检查和代码复用。
interface IPerson { name: string; age: number; } function displayPerson(person: IPerson) { console.log(`Name: ${person.name}, Age: ${person.age}`); } let person: IPerson = { name: "TypeScript", age: 25 }; displayPerson(person); // 输出 "Name: TypeScript, Age: 25"
接口还可以用于扩展类型:
interface IPerson { name: string; age: number; } interface IStudent extends IPerson { grade: string; } let student: IStudent = { name: "TypeScript", age: 25, grade: "A" }; console.log(student); // 输出 { name: "TypeScript", age: 25, grade: "A" }
类可以实现接口来保证类遵循接口定义的结构:
interface IHasAge { age: number; } class Student implements IHasAge { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } let student = new Student("TypeScript", 25); console.log(student); // 输出 { name: "TypeScript", age: 25 }
泛型是一种允许函数、类或接口在编写时不必指定具体的类型,而可以在使用时指定类型的机制。
下面是一个简单的泛型函数示例:
function identity<T>(arg: T): T { return arg; } let output = identity<string>("TypeScript"); console.log(output); // 输出 "TypeScript"
泛型类允许类方法接受任何类型的参数:
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; } } let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y); console.log(myGenericNumber.add(1, 2)); // 输出 3
装饰器是一种特殊的声明,可以在编译时修改类的行为。装饰器通过 @
符号来标注。
方法装饰器通常用来增强或修改类的方法行为:
function log(target: any, name: string, descriptor: PropertyDescriptor) { let originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Calling "${name}" with`, args); return originalMethod.apply(this, args); }; return descriptor; } class Math { @log add(a: number, b: number) { return a + b; } } let math = new Math(); console.log(math.add(2, 3)); // 输出 "Calling "add" with [ 2, 3 ]" 和 5
类装饰器通常用来修改类的构造函数或原型。
function readonly(target: any) { let prototype = target.prototype; for (let key of Object.keys(prototype)) { let descriptor: PropertyDescriptor = Object.getOwnPropertyDescriptor(prototype, key); if (descriptor && typeof descriptor.set === 'function') { descriptor.set = null; } } return target; } @readonly class Person { name: string; constructor(name: string) { this.name = name; } } let person = new Person("TypeScript"); person.name = "New TypeScript"; // 这里会报错,因为 descriptor.set 被设置为 null
修饰符用于指定类成员(如属性和方法)的访问级别和行为。常见的修饰符包括 public
、private
和 protected
。
public
修饰符表示属性和方法是公共的,可以被类的实例直接访问:
class Person { public name: string; public age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } let person = new Person("TypeScript", 25); console.log(person.name); // 输出 "TypeScript"
private
修饰符表示属性和方法是私有的,只能在类内部访问:
class Person { private name: string; private age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } private getAge() { return this.age; } } let person = new Person("TypeScript", 25); console.log(person.getAge()); // 这里会报错,因为 getAge 是私有方法
protected
修饰符表示属性和方法是受保护的,可以在类及其子类中访问:
class Animal { protected name: string; constructor(name: string) { this.name = name; } } class Dog extends Animal { bark() { console.log(`${this.name} says Woof!`); } } let dog = new Dog("Buddy"); dog.bark(); // 输出 "Buddy says Woof!"
继承允许一个类继承另一个类的属性和方法。被继承的类称为基类或父类,继承的类称为派生类或子类。
class Animal { name: string; constructor(name: string) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } class Dog extends Animal { breed: string; constructor(name: string, breed: string) { super(name); this.breed = breed; } bark() { console.log(`${this.name} barks.`); } } let dog = new Dog("Buddy", "Labrador"); dog.speak(); // 输出 "Buddy makes a noise." dog.bark(); // 输出 "Buddy barks."
接口用于定义成员(属性和方法)的结构,以便在类中实现。
interface IPerson { name: string; age: number; } class Student implements IPerson { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } let student = new Student("TypeScript", 25); console.log(student); // 输出 { name: "TypeScript", age: 25 }
类型别名用于创建新的类型名称,使得代码更具可读性和可维护性。
type IPerson = { name: string; age: number; }; let person: IPerson = { name: "TypeScript", age: 25 }; console.log(person); // 输出 { name: "TypeScript", age: 25 }
泛型接口和类允许定义接口和类时使用类型参数。
interface IGeneric<T> { value: T; } class GenericClass<T> implements IGeneric<T> { value: T; constructor(value: T) { this.value = value; } } let genericNumber: IGeneric<number> = { value: 123 }; let genericString: IGeneric<string> = { value: "TypeScript" }; let genericClassNumber = new GenericClass<number>(123); let genericClassString = new GenericClass<string>("TypeScript"); console.log(genericNumber.value); // 输出 123 console.log(genericString.value); // 输出 "TypeScript" console.log(genericClassNumber.value); // 输出 123 console.log(genericClassString.value); // 输出 "TypeScript"
面试时,经常会问到 TypeScript 中的基本类型和变量声明。例如:
let age: number = 25; let name: string = "TypeScript"; let isStudent: boolean = true;
常见的问题还包括类的继承、接口的使用和泛型的应用。例如:
interface IPerson { name: string; age: number; } class Student implements IPerson { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } let student = new Student("TypeScript", 25);
面试中也会涉及到泛型的使用,例如定义泛型函数、泛型类和泛型接口:
function identity<T>(arg: T): T { return arg; } let output = identity<string>("TypeScript"); console.log(output); // 输出 "TypeScript"
装饰器是一种高级特性,面试中会询问如何定义和使用装饰器:
function log(target: any, name: string, descriptor: PropertyDescriptor) { let originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Calling "${name}" with`, args); return originalMethod.apply(this, args); }; return descriptor; } class Math { @log add(a: number, b: number) { return a + b; } } let math = new Math(); console.log(math.add(2, 3)); // 输出 "Calling "add" with [ 2, 3 ]" 和 5
假设你正在开发一个简单的博客应用,使用 TypeScript 来编写后端 API。这个项目将涵盖 TypeScript 的许多高级特性,包括类、接口、泛型和装饰器等。
/blog-api /src /controllers /postController.ts /models /post.ts /services /postService.ts /types /Post.ts index.ts main.ts /tsconfig.json
该项目将实现以下功能:
控制器用于处理 HTTP 请求并调用服务层。
// src/controllers/postController.ts import { PostService } from '../services/postService'; import { Post } from '../models/post'; import { Post as PostType } from '../types/Post'; class PostController { private postService: PostService; constructor(postService: PostService) { this.postService = postService; } async createPost(title: string, content: string): Promise<PostType> { const newPost = new Post(title, content); return this.postService.create(newPost); } async getPostById(id: number): Promise<PostType | null> { return this.postService.getById(id); } async updatePost(id: number, title: string, content: string): Promise<PostType | null> { return this.postService.update(id, title, content); } async deletePost(id: number): Promise<boolean> { return this.postService.delete(id); } } export default new PostController(new PostService());
服务层用于处理业务逻辑。
// src/services/postService.ts import { Post } from '../models/post'; import { Post as PostType } from '../types/Post'; class PostService { private posts: Post[] = []; create(post: Post): PostType { this.posts.push(post); return post; } getById(id: number): PostType | null { return this.posts.find(post => post.id === id) || null; } update(id: number, title: string, content: string): PostType | null { const post = this.getById(id); if (post) { post.title = title; post.content = content; return post; } return null; } delete(id: number): boolean { const postIndex = this.posts.findIndex(post => post.id === id); if (postIndex > -1) { this.posts.splice(postIndex, 1); return true; } return false; } } export default new PostService();
模型层用于定义数据结构。
// src/models/post.ts import { Post as PostType } from '../types/Post'; class Post implements PostType { id: number; title: string; content: string; constructor(title: string, content: string) { this.id = Date.now(); this.title = title; this.content = content; } } export default Post;
类型定义文件用于统一类型定义。
// src/types/Post.ts export interface Post { id: number; title: string; content: string; }
主程序用于启动应用。
// src/main.ts import { PostController } from './controllers/postController'; async function testBlogApi() { const postController = new PostController(new PostService()); const newPost = await postController.createPost("First Post", "This is my first blog post."); console.log("Created Post:", newPost); const retrievedPost = await postController.getPostById(newPost.id); console.log("Retrieved Post:", retrievedPost); } testBlogApi();
PostService
或 getPostById
。控制器用于处理 HTTP 请求并调用服务层。
// src/controllers/postController.ts import { PostService } from '../services/postService'; import { Post } from '../models/post'; import { Post as PostType } from '../types/Post'; class PostController { private postService: PostService; constructor(postService: PostService) { this.postService = postService; } async createPost(title: string, content: string): Promise<PostType> { const newPost = new Post(title, content); return this.postService.create(newPost); } async getPostById(id: number): Promise<PostType | null> { return this.postService.getById(id); } async updatePost(id: number, title: string, content: string): Promise<PostType | null> { return this.postService.update(id, title, content); } async deletePost(id: number): Promise<boolean> { return this.postService.delete(id); } } export default new PostController(new PostService());
服务层用于处理业务逻辑。
// src/services/postService.ts import { Post } from '../models/post'; import { Post as PostType } from '../types/Post'; class PostService { private posts: Post[] = []; create(post: Post): PostType { this.posts.push(post); return post; } getById(id: number): PostType | null { return this.posts.find(post => post.id === id) || null; } update(id: number, title: string, content: string): PostType | null { const post = this.getById(id); if (post) { post.title = title; post.content = content; return post; } return null; } delete(id: number): boolean { const postIndex = this.posts.findIndex(post => post.id === id); if (postIndex > -1) { this.posts.splice(postIndex, 1); return true; } return false; } } export default new PostService();
模型层用于定义数据结构。
// src/models/post.ts import { Post as PostType } from '../types/Post'; class Post implements PostType { id: number; title: string; content: string; constructor(title: string, content: string) { this.id = Date.now(); this.title = title; this.content = content; } } export default Post;
类型定义文件用于统一类型定义。
// src/types/Post.ts export interface Post { id: number; title: string; content: string; }
console.log
语句,输出变量值和函数执行情况。以下是一个简单的示例,展示了如何创建和获取博客文章:
// src/main.ts import { PostController } from './controllers/postController'; async function testBlogApi() { const postController = new PostController(new PostService()); const newPost = await postController.createPost("First Post", "This is my first blog post."); console.log("Created Post:", newPost); const retrievedPost = await postController.getPostById(newPost.id); console.log("Retrieved Post:", retrievedPost); } testBlogApi();
通过以上示例,可以看到如何构建一个简单的博客应用,并展示了 TypeScript 的一些高级特性。希望这些示例能帮助你在实际项目中更好地应用 TypeScript。
本教程涵盖了 TypeScript 的基础概念、高级特性以及如何在实际项目中应用这些概念。重点介绍了以下内容:
推荐一些在线学习资源,帮助你进一步学习和掌握 TypeScript:
希望这些资源能帮助你在 TypeScript 的学习之路上不断进步。