本文详细介绍了TypeScript的基础概念与语法,包括变量声明、类型推断、接口定义和类的使用等。文章还提供了TS大厂面试真题的实际演练和解析,帮助读者深入理解并掌握关键知识点。此外,文章还分享了面试中的技巧与策略,帮助读者更好地准备和应对TS相关的技术面试。
TS基础概念与语法介绍 变量与类型声明变量
在 TypeScript 中,可以通过 let
或 const
关键字来声明变量。声明变量时,可以指定类型,也可以使用类型推断。
// 显式声明类型
let age: number = 25;
const name: string = "John Doe";
// 类型推断
let message = "Hello, TypeScript!";
类型推断
TypeScript 通过类型推断来确定变量的类型。如果在声明时没有明确指定类型,TypeScript 会根据赋值来确定变量的类型。
let message = "Hello, TypeScript!";
// 类型推断为 string
console.log(message);
变量提升
在 TypeScript 中,变量声明会被提升到其所在作用域的顶部。这意味着可以在声明之前使用变量,但必须在声明之前声明它们。
console.log(age); // 输出 undefined
let age = 25;
常量提升
与变量不同,const
声明不会提升。如果在声明之前使用 const
,会抛出引用错误。
// console.log(name); // 抛出 ReferenceError
const name = "John Doe";
数组与元组
数组
在 TypeScript 中,可以通过 Array
类型或数组类型注解来声明数组。
let numbers: number[] = [1, 2, 3, 4, 5];
let names: Array<string> = ["Alice", "Bob", "Charlie"];
元组
元组允许你声明具有固定数量和类型元素的数组。元组中的元素可以有不同的类型。
let user: [string, number];
user = ["Alice", 25];
console.log(user[0], user[1]); // 输出 Alice 25
函数
函数声明
在 TypeScript 中,可以使用函数声明来定义函数。函数声明可以指定参数类型和返回类型。
function add(a: number, b: number): number {
return a + b;
}
console.log(add(2, 3)); // 输出 5
函数表达式
函数表达式将函数作为值赋给一个变量。
let multiply = function (a: number, b: number): number {
return a * b;
};
console.log(multiply(2, 3)); // 输出 6
可选参数与默认值
在函数中,可以使用 ?
符号来定义可选参数。也可以为参数指定默认值。
function greet(name: string, message?: string): void {
console.log(`Hello, ${name}! ${message ? message : "Have a nice day!"}`);
}
greet("Alice"); // 输出 Hello, Alice! Have a nice day!
greet("Bob", "Good morning!"); // 输出 Hello, Bob! Good morning!
接口
接口定义
接口用于定义对象的结构。接口可以包含属性、方法和索引签名。
interface User {
name: string;
age: number;
greet(): void;
}
let user: User = {
name: "Alice",
age: 25,
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
};
user.greet(); // 输出 Hello, my name is Alice and I am 25 years old.
可选属性
接口中的属性可以被定义为可选,使用 ?
符号。
interface User {
name: string;
age?: number; // 可选属性
}
let user: User = {
name: "Alice"
};
console.log(user.name); // 输出 Alice
console.log(user.age); // 输出 undefined
读取索引签名
接口中的索引签名用于定义对象中键和值的类型。
interface User {
[key: string]: any;
}
let user: User = {
name: "Alice",
age: 25
};
console.log(user.name); // 输出 Alice
console.log(user.age); // 输出 25
类
类定义
类是对象的蓝图,可以定义类的属性、方法和构造函数。
class User {
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 user = new User("Alice", 25);
user.greet(); // 输出 Hello, my name is Alice and I am 25 years old.
继承
类可以通过 extends
关键字继承另一个类。继承的类会继承父类的所有属性和方法。
class Admin extends User {
role: string;
constructor(name: string, age: number, role: string) {
super(name, age);
this.role = role;
}
greet() {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old and my role is ${this.role}.`);
}
}
let admin = new Admin("Bob", 30, "Admin");
admin.greet(); // 输出 Hello, my name is Bob, I am 30 years old and my role is Admin.
泛型
泛型定义
泛型允许你编写可复用的函数或类,这些函数或类可以操作多种类型的值。
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("Hello, TypeScript!");
console.log(output); // 输出 Hello, TypeScript!
泛型接口
泛型接口允许你定义可以用于多种类型的接口。
interface GenericIdentity<T> {
(arg: T): T;
}
let identity: GenericIdentity<number> = (arg: number) => arg;
console.log(identity(25)); // 输出 25
泛型约束
泛型约束用于限制泛型类型,使其满足某些条件。
interface Lengthwise {
length: number;
}
function identity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 长度属性确保了类型具有 length 属性
return arg;
}
let output = identity({ length: 10, value: "Hello" });
console.log(output); // 输出 { length: 10, value: "Hello" }
常见的TS面试题目解析
1. 解释TypeScript中变量声明的提升
在TypeScript中,变量声明会被提升到其所在作用域的顶部。这意味着可以在声明之前使用变量,但必须在声明之前声明它们。对于 let
和 const
声明来说,变量在声明之前会被提升为 undefined
,而 const
声明不会提升。
console.log(age); // 输出 undefined
let age = 25;
// console.log(name); // 抛出 ReferenceError
const name = "John Doe";
2. 什么是类型推断?它在TypeScript中如何工作?
类型推断是TypeScript根据赋值自动确定变量类型的过程。如果没有明确指定类型,TypeScript会根据赋值来确定变量的类型。
let message = "Hello, TypeScript!";
// 类型推断为 string
console.log(message);
3. 解释接口与类的区别
接口定义了对象的结构,接口可以包含属性、方法和索引签名。而类是对象的蓝图,可以定义类的属性、方法和构造函数。接口用于定义对象的形状,而类用于创建具体的对象实例。
interface User {
name: string;
age: number;
greet(): void;
}
class UserClass {
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.`);
}
}
4. 什么是泛型?它在TypeScript中如何使用?
泛型允许你编写可复用的函数或类,这些函数或类可以操作多种类型的值。泛型通过指定类型参数在函数或类定义中传递类型。
function identity<T>(arg: T): T {
return arg;
}
let output = identity<number>(25);
console.log(output); // 输出 25
5. 什么是类型断言?它在TypeScript中如何使用?
类型断言用于告诉编译器一个值具有某个特定的类型。类型断言有两种形式:<Type>expression
和 expression as Type
。
let someValue: any = "abc";
let strLength: number = (someValue as string).length;
大厂面试中TS的考察重点
1. 类型系统与类型推断
面试官可能会考察你对TypeScript类型系统和类型推断的理解,包括类型推断如何工作,如何在代码中使用类型推断。
// 示例代码
let age: number = 25;
const name: string = "John Doe";
// 类型推断
let message = "Hello, TypeScript!";
console.log(message);
2. 接口与类
接口与类的概念是面试中常见的考察点,包括它们的区别、如何定义接口和类、如何使用接口和类。
// 示例代码
interface User {
name: string;
age: number;
greet(): void;
}
class UserClass {
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.`);
}
}
3. 泛型
面试官可能会考察你对泛型的理解,包括如何定义泛型函数和泛型类,以及如何使用泛型约束。
// 示例代码
function identity<T>(arg: T): T {
return arg;
}
let output = identity<number>(25);
console.log(output);
4. 代码质量与最佳实践
面试官可能会考察你的代码风格和代码质量,包括最佳实践、如何编写可维护的代码、如何避免常见的陷阱和错误。
// 示例代码
function sumArray(arr: number[]): number {
return arr.reduce((acc, val) => acc + val, 0);
}
let numbers = [1, 2, 3, 4, 5];
let sum = sumArray(numbers);
console.log(sum);
5. 项目经验与实际应用
面试官可能会考察你在实际项目中使用TypeScript的经验,包括你如何在项目中使用TypeScript,你遇到过哪些挑战,你是如何解决这些挑战的。
// 示例代码
class Admin extends User {
role: string;
constructor(name: string, age: number, role: string) {
super(name, age);
this.role = role;
}
greet() {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old and my role is ${this.role}.`);
}
}
let admin = new Admin("Bob", 30, "Admin");
admin.greet();
TS面试真题实战演练
1. 题目一
题目描述:给定一个数组,编写一个函数将数组中的元素类型推断为 number,并返回数组的和。
function sumArray(arr: any[]): number {
return arr.reduce((acc, val) => acc + val, 0);
}
let numbers = [1, 2, 3, 4, 5];
let sum = sumArray(numbers);
console.log(sum); // 输出 15
2. 题目二
题目描述:给定一个对象,编写一个函数检查对象是否包含某个属性,并返回该属性的值。
function getProperty(obj: any, key: string): any {
return key in obj ? obj[key] : undefined;
}
let user = { name: "Alice", age: 25 };
let name = getProperty(user, "name");
let address = getProperty(user, "address"); // undefined
console.log(name); // 输出 Alice
console.log(address); // 输出 undefined
3. 题目三
题目描述:给定一个对象和一个键,编写一个函数将对象中的键值对添加到另一个对象中。
function addProperty(target: any, key: string, value: any): void {
target[key] = value;
}
let user = {};
addProperty(user, "name", "Alice");
addProperty(user, "age", 25);
console.log(user); // 输出 { name: "Alice", age: 25 }
4. 题目四
题目描述:给定一个泛型类型,编写一个函数将对象中的键值对添加到另一个对象中。
function addProperty<T extends object, K extends keyof T>(target: T, key: K, value: T[K]): void {
target[key] = value;
}
let user = {} as { name: string, age: number };
addProperty(user, "name", "Alice");
addProperty(user, "age", 25);
console.log(user); // 输出 { name: "Alice", age: 25 }
5. 题目五
题目描述:给定一个数组,编写一个函数将数组中的元素类型推断为 number,并返回数组的平均值。
function averageArray(arr: any[]): number {
return arr.reduce((acc, val) => acc + val, 0) / arr.length;
}
let numbers = [1, 2, 3, 4, 5];
let avg = averageArray(numbers);
console.log(avg); // 输出 3
解答TS面试题的技巧与策略
1. 避免手动转换类型
在使用TypeScript时,尽量避免手动转换类型,尽量使用类型推断和类型断言。手动转换类型会导致代码更难以维护和理解。
let someValue: any = "abc";
let length = (someValue as string).length;
console.log(length);
2. 使用泛型提高代码复用性
在编写函数和类时,使用泛型可以提高代码的复用性。泛型允许你编写可复用的代码,这些代码可以操作多种类型的值。
function identity<T>(arg: T): T {
return arg;
}
3. 使用接口定义对象的形状
使用接口定义对象的形状是一种良好的实践。接口可以定义对象的结构,包括属性、方法和索引签名。
interface User {
name: string;
age: number;
}
4. 使用类创建具体的对象实例
使用类创建具体的对象实例是一种良好的实践。类是对象的蓝图,可以定义类的属性、方法和构造函数。
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
5. 使用最佳实践编写可维护的代码
使用最佳实践编写可维护的代码是一种良好的实践。最佳实践包括代码风格、命名约定、注释和文档等。
function averageArray(arr: number[]): number {
return arr.reduce((acc, val) => acc + val, 0) / arr.length;
}
面试准备与心态调整技巧
1. 掌握基础概念与语法
掌握TypeScript的基础概念和语法是面试的重要准备。确保你理解变量与类型、数组与元组、函数、接口、类、泛型等基本概念。
// 示例代码
let age: number = 25;
const name: string = "John Doe";
// 类型推断
let message = "Hello, TypeScript!";
console.log(message);
2. 练习编写高质量代码
练习编写高质量代码是面试的重要准备。确保你能够编写清晰、简洁、可维护的代码。练习编写可复用的代码,避免重复造轮子。
// 示例代码
function averageArray(arr: number[]): number {
return arr.reduce((acc, val) => acc + val, 0) / arr.length;
}
let numbers = [1, 2, 3, 4, 5];
let avg = averageArray(numbers);
console.log(avg);
3. 准备项目经验与实际应用
准备项目经验与实际应用是面试的重要准备。确保你能够描述你在实际项目中使用TypeScript的经验,包括你遇到的挑战和你是如何解决这些挑战的。
// 示例代码
class Admin extends User {
role: string;
constructor(name: string, age: number, role: string) {
super(name, age);
this.role = role;
}
greet() {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old and my role is ${this.role}.`);
}
}
let admin = new Admin("Bob", 30, "Admin");
admin.greet();
4. 保持积极的心态
保持积极的心态是面试的重要准备。面试可能会遇到一些挑战,但保持积极的心态可以帮助你更好地应对这些挑战。相信自己的能力,保持自信。
// 示例代码
let age: number = 25;
const name: string = "John Doe";
console.log(`Hello, ${name}! Your age is ${age}.`);
5. 练习模拟面试
练习模拟面试是面试的重要准备。模拟面试可以帮助你熟悉面试的过程,提高你的面试技巧。可以邀请朋友或同事帮助你进行模拟面试。
// 示例代码
function averageArray(arr: number[]): number {
return arr.reduce((acc, val) => acc + val, 0) / arr.length;
}
let numbers = [1, 2, 3, 4, 5];
let avg = averageArray(numbers);
console.log(avg);
6. 保持耐心与专注
保持耐心与专注是面试的重要准备。面试可能会遇到一些挑战,但保持耐心与专注可以帮助你更好地应对这些挑战。保持冷静,认真回答每一个问题。
// 示例代码
function sumArray(arr: number[]): number {
return arr.reduce((acc, val) => acc + val, 0);
}
let numbers = [1, 2, 3, 4, 5];
let sum = sumArray(numbers);
console.log(sum);
7. 准备常见面试问题
准备常见面试问题是面试的重要准备。确保你能够回答一些常见的面试问题,包括解释TypeScript中的变量声明、类型推断、接口与类的区别、泛型的概念等。
// 示例代码
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("Hello, TypeScript!");
console.log(output);