MST
星途 面试题库

面试题:结合设计哲学分析复杂场景下顶层和底层类型运用

在一个大型 TypeScript 项目中,存在多个模块相互依赖,模块间传递的数据类型复杂。请基于 `TypeScript顶层类型与底层类型设计哲学`,分析在处理错误处理机制、通用函数设计以及模块接口定义这几个方面,如何巧妙且合理地运用顶层类型与底层类型,以提升代码的健壮性和可维护性,并给出具体的代码架构示例及详细解释。
24.7万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

1. 错误处理机制

  • 顶层类型的运用:使用顶层类型 unknown 来表示未知类型的错误。当捕获到一个错误时,最初我们并不知道它的确切类型,unknown 是最安全的选择。这可以防止意外的类型错误,因为 unknown 类型不能直接操作,必须经过类型检查或断言后才能使用。
try {
    // 可能抛出错误的代码
    const result = someFunctionThatMightThrow();
} catch (error) {
    let errorMessage: string;
    if (typeof error === 'string') {
        errorMessage = error;
    } else if (error instanceof Error) {
        errorMessage = error.message;
    } else {
        errorMessage = 'Unknown error occurred';
    }
    console.error(errorMessage);
}

这里将 catch 块中的 error 类型默认为 unknown,通过类型检查来安全地提取错误信息。

  • 底层类型的运用:对于自定义错误类型,定义底层具体类型。例如,我们可以创建特定的错误类继承自 Error 类,这样在捕获错误时可以更精确地处理不同类型的错误。
class MyCustomError extends Error {
    constructor(message: string) {
        super(message);
        this.name = 'MyCustomError';
    }
}

function someFunctionThatMightThrow() {
    throw new MyCustomError('This is a custom error');
}

try {
    someFunctionThatMightThrow();
} catch (error) {
    if (error instanceof MyCustomError) {
        console.error(`Caught custom error: ${error.message}`);
    } else {
        console.error('Caught other error');
    }
}

2. 通用函数设计

  • 顶层类型的运用:在设计通用函数时,使用顶层类型 anyunknown 作为参数类型,如果函数需要接受任何类型的数据。但是 unknown 更安全,因为它强制进行类型检查。例如,一个通用的日志记录函数:
function logValue(value: unknown) {
    if (typeof value ==='string') {
        console.log(`String value: ${value}`);
    } else if (typeof value === 'number') {
        console.log(`Number value: ${value}`);
    } else {
        console.log('Other type of value');
    }
}

logValue('Hello');
logValue(123);
  • 底层类型的运用:使用底层类型来约束函数返回值或特定参数的精确类型。比如一个计算两个数字之和的函数:
function addNumbers(a: number, b: number): number {
    return a + b;
}

3. 模块接口定义

  • 顶层类型的运用:在模块接口定义中,如果需要表示一些灵活的、未确定类型的数据结构,可以使用顶层类型。例如,一个配置文件读取模块,其返回的配置对象可能包含各种类型的数据。
// config.ts
interface Config {
    [key: string]: unknown;
}

export function loadConfig(): Config {
    // 从文件或其他地方加载配置
    return {
        serverAddress: '127.0.0.1',
        port: 3000,
        isDebug: true
    };
}

这里使用 unknown 来允许配置对象包含任意类型的值,同时保持类型安全。

  • 底层类型的运用:对于模块间传递的核心数据结构,定义精确的底层类型接口。例如,一个用户信息模块,定义用户信息的精确类型:
// user.ts
export interface User {
    id: number;
    name: string;
    email: string;
}

export function getUser(): User {
    return {
        id: 1,
        name: 'John Doe',
        email: 'johndoe@example.com'
    };
}

这样在其他模块使用 User 类型时,能确保数据结构的一致性和类型安全,提升代码的健壮性和可维护性。