面试题答案
一键面试项目结构设计
- 目录结构:
project/ ├── src/ │ ├── models/ │ │ ├── user.ts │ ├── services/ │ │ ├── userService.ts │ ├── main.ts ├── tsconfig.json
models/user.ts
:- 接口定义:
// 定义用户接口 export interface User { id: number; name: string; age: number; }
- 类定义:
// 用户类,实现User接口 export class UserClass implements User { constructor(public id: number, public name: string, public age: number) {} }
- 接口定义:
services/userService.ts
:- 泛型函数定义:
import { User, UserClass } from '../models/user'; // 泛型函数,用于从数组中找到符合条件的用户 export function findUser<T extends User>(users: T[], condition: (user: T) => boolean): T | undefined { return users.find(condition); }
- 泛型函数定义:
main.ts
:- 模块导入与使用:
import { UserClass } from './models/user'; import { findUser } from './services/userService'; // 创建用户数组 const users: UserClass[] = [ new UserClass(1, 'Alice', 25), new UserClass(2, 'Bob', 30) ]; // 使用类型守卫进行类型推断 const foundUser = findUser(users, user => user.age > 25); if (foundUser) { console.log(`Found user: ${foundUser.name}`); } // 条件类型示例 type IsUserOver30<T extends User> = T extends { age: infer A } ? A extends number ? A > 30 : false : false; type UserIsOver30 = IsUserOver30<UserClass>; console.log(`UserIsOver30: ${UserIsOver30}`);
- 模块导入与使用:
tsconfig.json
:{ "compilerOptions": { "target": "ES6", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src"] }
设计思路解释
- 模块划分:通过将不同功能的代码划分到不同模块,如
models
存放数据模型相关代码,services
存放业务逻辑相关代码,使得代码结构清晰,便于维护和管理。在不同模块间,通过import
和export
关键字来处理类型空间和值空间的导入导出。 - 类型推断:在
findUser
泛型函数中,TypeScript根据传入的数组类型自动推断T
的类型,确保在函数内部对user
的操作符合T
所代表的类型。在main.ts
中,foundUser
的类型根据findUser
的返回类型推断得出,并且通过if (foundUser)
这样的类型守卫,TypeScript能在块内准确推断foundUser
不为undefined
,从而保证类型空间和值空间的一致性。 - 类型守卫:
if (foundUser)
作为类型守卫,明确了foundUser
在块内是有值的,使得后续对foundUser
属性的访问是安全的,避免了运行时的undefined
错误,维护了类型空间和值空间的准确性。 - 条件类型:在
main.ts
中定义的IsUserOver30
条件类型,根据传入类型中age
字段的值来判断是否大于30。这展示了如何在类型空间中进行复杂的逻辑判断,并且与值空间中的数据逻辑相对应,确保类型定义与实际业务逻辑的一致性。通过这种方式,在整个项目中,类型空间和值空间紧密结合,共同保证代码的健壮性和准确性。