为了账号安全,请及时绑定邮箱和手机立即绑定

TypeScript面试题:新手必懂的基础知识与解答

概述

本文详细介绍了TypeScript的核心特性和常见面试题的解析,帮助读者理解TypeScript的基础知识和应用场景。文中不仅讲解了类型推断、数组类型、函数类型、接口与类以及泛型与装饰器等关键概念,还提供了丰富的示例代码以加深理解。此外,文章还深入分析了一些典型的TypeScript面试题,确保读者能够掌握TypeScript面试中常见的知识点和解题思路。

TypeScript简介与特性

TypeScript是JavaScript的一个超集,由微软开发,旨在为JavaScript提供静态类型检查和更强大的工具支持。TypeScript的设计原则是保持与JavaScript的兼容性,同时提供更强大的类型系统和其他功能,使得开发者能够编写出更安全、更易于维护的代码。

TypeScript的核心特性

1. 静态类型检查

TypeScript引入了静态类型检查系统,允许开发者在代码编写阶段就发现潜在的类型错误,从而减少运行时的错误。开发者可以在变量、函数参数、返回值等地方定义类型,TypeScript编译器会在编译时检查这些类型是否一致,如果不一致,编译器会给出类型错误信息。

示例代码:

let age: number = 30;
age = "thirty"; // 编译错误,因为age定义为number类型,但此处试图赋值为字符串"thirty"

2. 类支持

TypeScript完全支持ES6的类特性,使得开发者能够更方便地进行面向对象编程。类支持继承、构造函数、静态成员等,使得代码组织更加清晰。

示例代码:

class Animal {
    constructor(public name: string) {}
    makeSound(): void {
        console.log('Some generic sound');
    }
}

class Dog extends Animal {
    makeSound(): void {
        console.log('Woof!');
    }
}

const myDog = new Dog('Rex');
myDog.makeSound(); // 输出:Woof!

3. 接口定义

TypeScript的接口定义明确的类型结构,使得开发者能够定义复杂的对象结构、函数类型,并且确保这些类型在使用时的一致性。

示例代码:

interface Point {
    x: number;
    y: number;
}

let point: Point = { x: 10, y: 20 };
console.log(point.x, point.y); // 输出:10 20

4. 模块支持

TypeScript支持ES6模块系统,允许开发者将代码组织成模块,便于代码的复用和组织。开发者可以使用export关键字导出模块中的内容,并使用import关键字导入其他模块的内容。

示例代码:

// 文件:mathLib.ts
export function add(a: number, b: number) {
    return a + b;
}

// 文件:main.ts
import { add } from './mathLib';
console.log(add(5, 3)); // 输出:8

5. 泛型

TypeScript的泛型使得函数、类或接口能够处理多种类型的数据,而无需指定具体的类型。这使得代码更加灵活和通用。

示例代码:

function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>('Hello, world!'); // 把类型参数声明为字符串
console.log(output); // 输出:Hello, world!

6. 装饰器

TypeScript支持ES7的装饰器特性,允许开发者在类、方法或属性上定义装饰器,从而在不修改原有代码的情况下,增强代码功能或进行AOP(面向切面编程)。

示例代码:

function log(target: any, name: string | symbol) {
    console.log(`Property accessed: ${name}`);
}

class User {
    @log
    name: string = 'John Doe';
}

const user = new User();
user.name; // 输出:Property accessed: name
基础类型详解

TypeScript中的类型分为基础类型和复杂类型两大类。基础类型是最常见的类型,包括数字、字符串、布尔值等。复杂类型则包括数组、元组等更为复杂的类型结构。

基本类型

1. number类型

number类型用于表示数字,可以是整数或浮点数。

示例代码:

let age: number = 30;
age = 30.5; // 正确,浮点数也是number类型
age = 'thirty'; // 编译错误,因为age定义为number类型

2. string类型

string类型用于表示文本字符串。

示例代码:

let message: string = 'Hello, World!';
message = '你好,世界!'; // 正确,支持中文
message = 123; // 编译错误,因为message定义为string类型

3. boolean类型

boolean类型用于表示布尔值,值可以是truefalse

示例代码:

let isCompleted: boolean = true;
isCompleted = 1; // 编译错误,因为isCompleted定义为boolean类型

4. void类型

void类型用于表示函数没有返回值。

示例代码:

function greet(): void {
    console.log('Hello!');
}

let result: void = greet(); // result的类型为void

5. null和undefined类型

nullundefined类型用于表示空值和未定义值。

示例代码:

let empty: null = null;
let notDefined: undefined = undefined;

6. any类型

any类型用于表示任何类型的值。如果不确定变量的类型,可以将类型声明为any,但使用any类型会失去类型检查的好处。

示例代码:

let age: any = 30;
age = 'thirty'; // 正确,因为age类型为any
复杂类型

1. 数组类型

数组类型用于表示固定类型的数据集合,可以通过[]操作符声明数组类型。

示例代码:

let numbers: number[] = [1, 2, 3];
numbers.push(4); // 正确,因为numbers是一个number类型的数组
numbers.push('four'); // 编译错误,因为numbers是一个number类型的数组

2. 元组类型

元组类型用于表示固定长度的数组,每个位置可以有不同的类型。

示例代码:

let person: [string, number] = ['John', 30];
person.push('Engineer'); // 编译错误,因为元组的长度固定为2
console.log(person[0], person[1]); // 输出:John 30

3. 对象类型

对象类型用于表示具有固定属性的对象,可以通过对象字面量声明对象类型。

示例代码:

interface User {
    name: string;
    age: number;
}

let user: User = { name: 'John Doe', age: 30 };
user = { name: 'Jane Doe', age: 25, country: 'China' }; // 编译错误,因为user对象多了country属性

4. 类型别名

类型别名用于为现有类型定义一个新名称。

示例代码:

type Point = {
    x: number;
    y: number;
};

let p: Point = { x: 10, y: 20 };
函数与接口

TypeScript中的函数和接口是两个重要的概念,它们有助于定义函数的行为和结构,确保代码的一致性和可维护性。

函数定义

在TypeScript中,可以定义函数的参数类型和返回值类型,以确保函数的输入和输出类型的一致性。

示例代码:

function add(a: number, b: number): number {
    return a + b;
}

let result: number = add(4, 5); // 调用函数并获取返回值
console.log(result); // 输出:9

函数的参数可以是可选的、可重复的,或者有默认值。

示例代码:

function add(a: number, b?: number): number {
    return a + (b || 0);
}

let result1: number = add(4); // 只传递第一个参数
let result2: number = add(4, 5); // 传递两个参数
console.log(result1, result2); // 输出:4 9

1. 可选参数

可选参数允许函数在调用时省略某些参数。

示例代码:

function greet(name: string, message?: string) {
    if (message) {
        console.log(`${name}, ${message}`);
    } else {
        console.log(`Hello, ${name}`);
    }
}

greet('Alice'); // 输出:Hello, Alice
greet('Bob', 'Good morning'); // 输出:Bob, Good morning

2. 默认参数

默认参数允许在没有提供实际参数值时使用默认值。

示例代码:

function greet(name: string, message: string = 'Hello') {
    console.log(`${message}, ${name}`);
}

greet('Alice'); // 输出:Hello, Alice
greet('Bob', 'Good morning'); // 输出:Good morning, Bob

3. 可变参数

可变参数允许在函数调用时传递不同数量的参数。

示例代码:

function add(...numbers: number[]): number {
    return numbers.reduce((sum, current) => sum + current, 0);
}

let result: number = add(1, 2, 3, 4); // 使用可变参数
console.log(result); // 输出:10
接口使用

接口在TypeScript中用于定义对象的结构,确保对象具有特定的属性和方法。接口可以用于函数参数、类成员等。

示例代码:

interface Point {
    x: number;
    y: number;
}

function printPoint(p: Point) {
    console.log(`Point (${p.x}, ${p.y})`);
}

let point: Point = { x: 10, y: 20 };
printPoint(point); // 输出:Point (10, 20)

接口还可以定义方法,确保对象具有特定的行为。

示例代码:

interface Calculator {
    add(a: number, b: number): number;
    subtract(a: number, b: number): number;
}

class BasicCalculator implements Calculator {
    add(a: number, b: number): number {
        return a + b;
    }

    subtract(a: number, b: number): number {
        return a - b;
    }
}

let calc: Calculator = new BasicCalculator();
console.log(calc.add(4, 5)); // 输出:9
console.log(calc.subtract(4, 5)); // 输出:-1
类与继承

TypeScript中的类支持面向对象编程的核心特性,包括构造函数、属性、方法、静态成员和继承。

类的定义与使用

类是面向对象编程的基础,它允许开发者定义具有特定属性和方法的对象类型。

示例代码:

class Animal {
    constructor(public name: string) {}

    makeSound(): void {
        console.log('Some generic sound');
    }
}

let animal: Animal = new Animal('Generic Animal');
animal.makeSound(); // 输出:Some generic sound

在类中,可以定义公共(public)、私有(private)、受保护(protected)成员,以控制成员的访问权限。

示例代码:

class Animal {
    protected name: string;

    constructor(name: string) {
        this.name = name;
    }

    makeSound(): void {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Animal {
    bark(): void {
        console.log(`${this.name} barks`);
    }
}

let dog: Dog = new Dog('Rex');
dog.makeSound(); // 输出:Rex makes a sound
dog.bark(); // 输出:Rex barks

在类中,可以定义静态成员,这些成员属于类本身,而不是类的实例。

示例代码:

class Animal {
    static numberOfAnimals: number = 0;

    constructor() {
        Animal.numberOfAnimals++;
    }
}

let animal1: Animal = new Animal();
let animal2: Animal = new Animal();
console.log(Animal.numberOfAnimals); // 输出:2

1. 构造函数

构造函数是类的一个特殊方法,用于初始化新创建的对象实例。

示例代码:

class Point {
    constructor(public x: number, public y: number) {}

    toString(): string {
        return `(${this.x}, ${this.y})`;
    }
}

let origin: Point = new Point(0, 0);
console.log(origin.toString()); // 输出:(0, 0)

2. 静态成员

静态成员属于类本身,而不是类的实例,可以通过类名直接访问。

示例代码:

class MathUtils {
    static PI: number = 3.14;

    static square(x: number): number {
        return x * x;
    }
}

console.log(MathUtils.PI); // 输出:3.14
console.log(MathUtils.square(5)); // 输出:25
继承的概念与应用

继承允许一个类继承另一个类的属性和方法,从而实现代码复用和层次化结构。

示例代码:

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    makeSound(): void {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Animal {
    constructor(name: string) {
        super(name);
    }

    bark(): void {
        console.log(`${this.name} barks`);
    }
}

let dog: Dog = new Dog('Rex');
dog.makeSound(); // 输出:Rex makes a sound
dog.bark(); // 输出:Rex barks

在继承中,子类可以重写父类的方法,以提供特定的行为。

示例代码:

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    makeSound(): void {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Animal {
    constructor(name: string) {
        super(name);
    }

    makeSound(): void {
        console.log(`${this.name} barks`);
    }
}

let dog: Dog = new Dog('Rex');
dog.makeSound(); // 输出:Rex barks
泛型与装饰器

泛型和装饰器是TypeScript中较为高级的概念,它们提供了更灵活和强大的编程能力。

泛型基本概念

泛型允许定义函数、类或接口时指定类型的参数,使得代码更加通用和灵活。

示例代码:

function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>('Hello, world!'); // 把类型参数声明为字符串
console.log(output); // 输出:Hello, world!

泛型可以用于类和接口中,以表示泛型类型。

示例代码:

class Collection<T> {
    items: T[] = [];

    add(item: T): void {
        this.items.push(item);
    }

    get(index: number): T {
        return this.items[index];
    }
}

let numbers: Collection<number> = new Collection<number>();
numbers.add(1);
numbers.add(2);
console.log(numbers.get(0)); // 输出:1
装饰器使用入门

装饰器是一种元编程工具,允许在类、方法或属性上定义装饰器,从而在不修改原有代码的情况下,增强代码功能或进行AOP编程。

示例代码:

function log(target: any, name: string | symbol) {
    console.log(`Property accessed: ${name}`);
}

class User {
    @log
    name: string = 'John Doe';
}

const user = new User();
user.name; // 输出:Property accessed: name

装饰器可以用于方法的定义,以实现特定的行为增强。

示例代码:

function readonly(target: any, name: string, descriptor: PropertyDescriptor) {
    descriptor.writable = false;
    return descriptor;
}

class User {
    @readonly
    name: string = 'John Doe';

    getName(): string {
        return this.name;
    }
}

let user = new User();
console.log(user.getName()); // 输出:John Doe
user.name = 'Jane Doe'; // 报错,因为name属性已设置为只读
实战:TypeScript面试题解析

在面试中,了解TypeScript的基础知识是必要的。下面是一些常见的面试题类型及其示例代码解析。

常见面试题类型

1. 类型推断

在TypeScript中,编译器可以根据变量的初始值推断出变量的类型。

示例代码:

let age = 30; // 编译器推断age为number类型
let message = 'Hello, world!'; // 编译器推断message为string类型

2. 数组类型

理解数组类型的定义和使用。

示例代码:

let numbers: number[] = [1, 2, 3];
numbers.push(4); // 正确,因为numbers是一个number类型的数组

3. 函数类型

理解函数的参数类型和返回值类型。

示例代码:

function add(a: number, b: number): number {
    return a + b;
}

let result: number = add(4, 5); // 调用函数并获取返回值

4. 接口与类

理解接口和类的定义、继承和实现。

示例代码:

interface Animal {
    name: string;
    makeSound(): void;
}

class Dog implements Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    makeSound(): void {
        console.log(`${this.name} barks`);
    }
}

let dog: Dog = new Dog('Rex');
dog.makeSound(); // 输出:Rex barks

5. 泛型与装饰器

理解泛型和装饰器的基本概念及其使用。

示例代码:

function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>('Hello, world!'); // 把类型参数声明为字符串
console.log(output); // 输出:Hello, world!

function log(target: any, name: string | symbol) {
    console.log(`Property accessed: ${name}`);
}

class User {
    @log
    name: string = 'John Doe';
}

const user = new User();
user.name; // 输出:Property accessed: name
示例代码解析

1. 类型推断

let age = 30; // 编译器推断age为number类型
let message = 'Hello, world!'; // 编译器推断message为string类型

这里,编译器根据变量的初始值自动推断出变量的类型。对于age,初始值为30,因此age被推断为number类型。对于message,初始值为字符串'Hello, world!',因此message被推断为string类型。

2. 数组类型

let numbers: number[] = [1, 2, 3];
numbers.push(4); // 正确,因为numbers是一个number类型的数组

这里,numbers是一个number类型的数组。push方法用于向数组中添加元素。由于numbers是一个number类型的数组,因此只能添加number类型的元素。这里添加4是正确的,但添加字符串或其他类型会引发编译错误。

3. 函数类型

function add(a: number, b: number): number {
    return a + b;
}

let result: number = add(4, 5); // 调用函数并获取返回值

这里,add函数接受两个number类型的参数,并返回一个number类型的值。result变量用于保存add函数的返回值,其类型为number

4. 接口与类

interface Animal {
    name: string;
    makeSound(): void;
}

class Dog implements Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    makeSound(): void {
        console.log(`${this.name} barks`);
    }
}

let dog: Dog = new Dog('Rex');
dog.makeSound(); // 输出:Rex barks

这里,Animal接口定义了一个name属性和一个makeSound方法。Dog类实现了Animal接口,包含一个name属性和一个makeSound方法。创建一个Dog实例并调用makeSound方法,输出Rex barks

5. 泛型与装饰器

function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>('Hello, world!'); // 把类型参数声明为字符串
console.log(output); // 输出:Hello, world!

function log(target: any, name: string | symbol) {
    console.log(`Property accessed: ${name}`);
}

class User {
    @log
    name: string = 'John Doe';
}

const user = new User();
user.name; // 输出:Property accessed: name

这里,identity函数是一个泛型函数,接受一个类型参数T,返回一个T类型的值。output变量调用identity函数时,类型参数T被指定为string,因此output的类型为string

log函数是一个装饰器,用于在属性访问时打印属性名。User类中的name属性被log装饰器装饰,当访问name属性时,会打印出Property accessed: name

以上是TypeScript面试题的一些常见类型及其示例代码解析,通过这些例子,希望你能更好地理解和掌握TypeScript的基础知识。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
手记
粉丝
14
获赞与收藏
86

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消