前端Typescript最常用 20 道面试题总结大全(含详细代码解析)
作者:全栈前端老曹
前言
以下是老曹关于TypeScript 最常用的 20 道面试题总结,TS是原生Js的超集,现如今已经是前端面试特别是中高级面试必问的问题,也是大工程项目必须掌握的技术了,以下涵盖类型系统、接口、泛型、类、装饰器、模块等核心知识点。每道题都包含详细解释和代码示例,适合大家对前端开发岗位的 TypeScript 技术面试准备,大家可以随时翻出来查阅背诵和练习!
1. TypeScript 和 JavaScript 的区别是什么?
问题: 解释 TypeScript 相比 JavaScript 增加了哪些特性?
答案:
- 类型系统(静态类型检查)。
 - 接口(Interface)与类型别名(Type)。
 - 泛型支持。
 - 装饰器(Decorators)。
 - 对象结构约束与可选属性。
 - 更好的 IDE 支持(自动补全、错误提示)。
 
// 示例:类型检查
function greet(name: string): void {
    console.log(`Hello, ${name}`);
}
greet("Tom"); // 正确
greet(123);   // 编译报错:参数类型不匹配
2. 如何定义变量并指定其类型?
问题: 定义一个 age 变量,并限制为数字类型。
答案:
使用类型注解语法。
let age: number = 25; age = "25"; // 报错:不能将字符串赋值给 number 类型
3. 什么是联合类型?如何使用?
问题: 定义一个函数参数可以是 string 或 number。
答案:
使用 | 表示联合类型。
function printId(id: number | string): void {
    console.log(`ID: ${id}`);
}
printId(101);      // OK
printId("101");    // OK
printId(true);     // 报错
4. 什么是类型断言?如何使用?
问题: 告诉编译器某个值的具体类型。
答案:
使用 <Type> 或 as Type。
const input = document.getElementById("username") as HTMLInputElement;
input.value = "默认值";
5. 接口(interface)和类型别名(type)的区别?
问题: interface Person {} vs type Person = {} 的区别。
答案:
| 特性 | interface | type | 
|---|---|---|
| 可扩展性 | 支持声明合并 | 不支持 | 
| 支持继承 | 支持 extends | 支持交叉类型 & | 
| 支持基本类型 | ❌ | ✅(如 `type ID = string | 
| 使用场景 | 对象结构建模 | 复杂类型组合 | 
// interface
interface User {
    name: string;
}
// type
type ID = string | number;
6. 如何定义可选属性?
问题: 在接口中定义一个可选的 age 属性。
答案:
使用 ? 标记可选属性。
interface Person {
    name: string;
    age?: number; // 可选
}
const p: Person = { name: "Alice" }; // 合法
7. 元组(Tuple)的作用是什么?如何定义?
问题: 创建一个元组表示 [姓名, 年龄]。
答案:
元组允许你定义数组中元素的类型顺序。
let user: [string, number]; user = ["Alice", 25]; // 合法 user = [25, "Alice"]; // 报错:类型顺序不符
8. 枚举(enum)有什么用途?如何定义?
问题: 定义一个表示星期的枚举。
答案:
枚举用于命名一组常量值。
enum WeekDay {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday
}
console.log(WeekDay.Monday); // 输出: 0
console.log(WeekDay[3]);     // 输出: "Thursday"
9. 泛型(Generic)的作用是什么?如何使用?
问题: 写一个通用的 identity 函数,返回传入的任意类型。
答案:
泛型让函数/类/接口具有更强的灵活性和复用性。
function identity<T>(value: T): T {
    return value;
}
console.log(identity<string>("hello")); // 输出: "hello"
console.log(identity<number>(123));     // 输出: 123
10. 类型推断(Type Inference)是什么?
问题: 如果没有显式标注类型,TS 如何确定类型?
答案:
TypeScript 会根据赋值自动推断类型。
let message = "Hello"; // 类型自动推断为 string message = 123; // 报错:不能将 number 赋值给 string
11. 如何定义函数类型?
问题: 定义一个函数类型,接受两个数字,返回一个数字。
答案:
使用类型表达式 type Fn = (a: number, b: number) => number;
type Sum = (a: number, b: number) => number; const add: Sum = (x, y) => x + y; console.log(add(2, 3)); // 输出: 5
12. 类型守卫(Type Guard)是什么?如何实现?
问题: 判断一个值是否是数字类型。
答案:
使用 typeof 或自定义谓词函数。
function isNumber(x: any): x is number {
    return typeof x === "number";
}
function processValue(value: number | string): void {
    if (isNumber(value)) {
        console.log(value.toFixed(2));
    } else {
        console.log(value.toUpperCase());
    }
}
13. 如何定义一个类?
问题: 创建一个 Person 类,有 name和 sayHello() 方法。
答案:
class Person {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    sayHello(): void {
        console.log(`Hello, my name is ${this.name}`);
    }
}
const p = new Person("Tom");
p.sayHello(); // 输出: Hello, my name is Tom
14. 类中的访问修饰符有哪些?分别代表什么含义?
问题: public、private 和 protected 的区别?
答案:
public:任何地方都可以访问(默认)。private:只能在类内部访问。protected:可在类及子类中访问。
class Animal {
    public name: string;
    private secret: string;
    protected family: string;
    constructor(name: string, secret: string, family: string) {
        this.name = name;
        this.secret = secret;
        this.family = family;
    }
}
class Dog extends Animal {
    showFamily() {
        console.log(this.family); // 合法
        // console.log(this.secret); // ILLEGAL
    }
}
15. 如何实现接口继承?
问题: 让 Employee 接口继承 Person 接口。
答案:
使用 extends 实现接口继承。
interface Person {
    name: string;
}
interface Employee extends Person {
    id: number;
}
const emp: Employee = { name: "John", id: 1 };
16. 如何定义只读属性?
问题: 定义一个不可修改的 id 字段。
答案:
使用 readonly 关键字。
interface User {
    readonly id: number;
    name: string;
}
const user: User = { id: 1, name: "Alice" };
user.id = 2; // 报错:无法修改只读属性
17. 装饰器(Decorator)是什么?如何使用?
问题: 写一个简单的类装饰器。
答案:
装饰器是一种特殊类型的声明,可用于类、方法、属性等。
function log(target: any, key: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        console.log(`Calling "${key}" with`, args);
        return originalMethod.apply(this, args);
    };
}
class Calculator {
    @log
    add(a: number, b: number): number {
        return a + b;
    }
}
const calc = new Calculator();
calc.add(2, 3);
// 输出: Calling "add" with [2, 3]
18.any和unknown的区别?
问题: any 和 unknown 在类型检查时有何不同?
答案:
any:绕过所有类型检查。unknown:必须先做类型检查后才能操作。
let value: unknown;
value = "hello";
if (typeof value === "string") {
    console.log(value.toUpperCase()); // 安全地使用
}
let val: any = 123;
val = "abc";
val = true;
console.log(val.foo.bar.baz); // 不会报错(但运行时报错)
19. 如何定义可索引类型?
问题: 创建一个对象,通过字符串索引获取值。
答案:
使用索引签名。
interface StringArray {
    [index: number]: string;
}
const arr: StringArray = ["Apple", "Banana"];
console.log(arr[0]); // 输出: "Apple"
interface Dictionary {
    [key: string]: number;
}
const data: Dictionary = { one: 1, two: 2 };
20. 如何使用never类型?
问题: 写一个总是抛出错误的函数,并返回 never。
答案:
never 表示永远不会返回值的函数。
function throwError(message: string): never {
    throw new Error(message);
}
function infiniteLoop(): never {
    while (true) {}
}
📋 总结表格
| 编号 | 题目描述 | 知识点 | 示例代码 | 常见考察点 | 
|---|---|---|---|---|
| 1 | TS 与 JS 区别 | 类型系统 | function greet(name: string) | 类型安全 | 
| 2 | 定义带类型的变量 | 类型注解 | let age: number = 25 | 基础语法 | 
| 3 | 联合类型 | ` | ` 操作符 | `id: string | 
| 4 | 类型断言 | 强制类型转换 | as HTMLElement | 类型信任机制 | 
| 5 | interface vs type | 类型定义方式 | interface A {} vs type A = {} | 接口设计 | 
| 6 | 可选属性 | ? 修饰符 | age?: number | 数据灵活性 | 
| 7 | 元组类型 | 固定长度数组 | [string, number] | 结构控制 | 
| 8 | 枚举类型 | 枚举值映射 | enum Status { Success, Failed } | 可读性增强 | 
| 9 | 泛型 | 参数化类型 | function identity<T>(value: T) | 通用性 | 
| 10 | 类型推断 | 自动识别类型 | let msg = "hello" | 类型安全 | 
| 11 | 函数类型定义 | 类型签名 | (a: number, b: number) => number | 函数编程 | 
| 12 | 类型守卫 | 运行时判断 | typeof value === 'number' | 类型细化 | 
| 13 | 类定义 | OOP 语法 | class Person { ... } | 面向对象 | 
| 14 | 类成员访问控制 | public, private, protected | private secret: string | 封装原则 | 
| 15 | 接口继承 | 扩展接口 | interface Employee extends Person | 接口设计 | 
| 16 | 只读属性 | readonly | readonly id: number | 数据不变性 | 
| 17 | 装饰器应用 | 类/方法增强 | @log() | 高阶拓展 | 
| 18 | any 与 unknown 区别 | 类型安全性 | value is unknown | 类型防御 | 
| 19 | 可索引类型 | 索引签名 | { [key: string]: number } | 动态对象 | 
| 20 | never 的用途 | 永远不返回 | function throwError(): never | 错误处理 | 
到此这篇关于前端Typescript最常用20道面试题的文章就介绍到这了,更多相关TS常用面试题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
