React + TypeScript 笔试题库

核心技术栈: UmiMax + React + Ant Design Pro + TypeScript

其他技术: Dva/Redux、ProComponents、Ahooks、Ant Design Charts


目录

  1. TypeScript 基础
  2. TypeScript 高级类型
  3. React + TypeScript
  4. UmiMax 相关
  5. Ant Design Pro 相关
  6. 泛型与工具类型
  7. 类型体操
  8. 实战编程题
  9. 架构设计题

TypeScript 基础

题目 1:类型推断

// 问:以下代码中,变量的类型是什么?

const a = 123;
const b = 'hello';
const c = [1, 2, 3];
const d = {
   
    name: 'Alice', age: 20 };
const e = [1, 'hello', true];

// 答案
// a: number
// b: string
// c: number[]
// d: { name: string; age: number; }
// e: (string | number | boolean)[]

题目 2:interface vs type

问:以下代码有什么问题?如何修复?

// 问题代码
type User = {
   
   
  name: string;
  age: number;
};

type User = {
   
   
  email: string;
};

// 答案:type 不能重复声明
// 修复方案 1:使用 interface
interface User {
   
   
  name: string;
  age: number;
}

interface User {
   
   
  email: string;
}
// 结果:User { name: string; age: number; email: string; }

// 修复方案 2:使用交叉类型
type User = {
   
   
  name: string;
  age: number;
} & {
   
   
  email: string;
};

题目 3:函数重载

实现一个函数,根据参数类型返回不同的结果

// 要求实现
function getValue(key: string): string;
function getValue(key: number): number;
function getValue(key: boolean): boolean;

// 答案
function getValue(key: string): string;
function getValue(key: number): number;
function getValue(key: boolean): boolean;
function getValue(key: string | number | boolean): string | number | boolean {
   
   
  if (typeof key === 'string') {
   
   
    return `String: ${
     
     key}`;
  } else if (typeof key === 'number') {
   
   
    return key * 2;
  } else {
   
   
    return !key;
  }
}

// 测试
console.log(getValue('hello')); // "String: hello"
console.log(getValue(10));      // 20
console.log(getValue(true));    // false

题目 4:枚举类型

问:以下两种枚举有什么区别?

// 数字枚举
enum Status1 {
   
   
  Pending,
  Success,
  Failed,
}

// 字符串枚举
enum Status2 {
   
   
  Pending = 'PENDING',
  Success = 'SUCCESS',
  Failed = 'FAILED',
}

// 答案:
// 1. 数字枚举支持反向映射,字符串枚举不支持
console.log(Status1[0]); // "Pending"
console.log(Status2['PENDING']); // undefined

// 2. 数字枚举会自增,字符串枚举需要手动赋值
// 3. 字符串枚举更易调试(查看网络请求时更清晰)
// 4. 推荐使用字符串枚举或 const enum

题目 5:类型守卫

实现一个类型守卫函数判断是否为字符串数组

// 实现 isStringArray
function processData(data: unknown) {
   
   
  if (isStringArray(data)) {
   
   
    // 这里 data 应该被推断为 string[]
    data.forEach((item) => console.log(item.toUpperCase()));
  }
}

// 答案
function isStringArray(value: unknown): value is string[] {
   
   
  return (
    Array.isArray(value) && 
    value.every((item) => typeof item === 'string')
  );
}

// 测试
processData(['a', 'b', 'c']); // 正常执行
processData([1, 2, 3]);       // 不会执行

TypeScript 高级类型

题目 6:联合类型与交叉类型

问:以下代码的输出类型是什么?

type A = {
   
    name: string; age: number };
type B = {
   
    name: string; email: string };

type C = A & B;
type D = A | B;

const c: C = {
   
   
  name: 'Alice',
  age: 20,
  email: 'alice@example.com',
};

const d1: D = {
   
    name: 'Bob', age: 25 };
const d2: D = {
   
    name: 'Charlie', email: 'charlie@example.com' };

// 答案:
// C = { name: string; age: number; email: string } (交叉类型,包含所有属性)
// D = A | B (联合类型,可以是 A 或 B)

题目 7:映射类型

实现一个将所有属性变为可选的工具类型

// 要求实现 MyPartial
type MyPartial<T> = ?;

// 测试
interface User {
   
   
  id: number;
  name: string;
  email: string;
}

type PartialUser = MyPartial<User>;
// 应该等价于
// { id?: number; name?: string; email?: string; }

// 答案
type MyPartial<T> = {
   
   
  [P in keyof T]?: T[P];
};

// 进阶:实现深度可选
type DeepPartial<T> = {
   
   
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

题目 8:条件类型

实现一个提取 Promise 返回值类型的工具

// 要求实现 UnwrapPromise
type UnwrapPromise<T> = ?;

// 测试
type A = UnwrapPromise<Promise<string>>; // string
type B = UnwrapPromise<Promise<number>>; // number
type C = UnwrapPromise<string>;          // string

// 答案
type UnwrapPromise<T> = T extends Promise<infer R> ? R : T;

// 进阶:支持嵌套 Promise
type DeepUnwrapPromise<T> = T extends Promise<infer R>
  ? DeepUnwrapPromise<R>
  : T;

type D = DeepUnwrapPromise<Promise<Promise<string>>>; // string

题目 9:infer 关键字

实现一个获取函数返回值类型的工具

// 要求实现 MyReturnType
type MyReturnType<T> = ?;

// 测试
function getUser() {
   
   
  return {
   
    name: 'Alice', age: 20 };
}

type User = MyReturnType<typeof getUser>;
// 应该是 { name: string; age: number }

// 答案
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// 扩展:获取函数参数类型
type MyParameters<T> = T extends (...args: infer P) => any ? P : never;

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

type Params = MyParameters<typeof add>; // [number, number]

题目 10:模板字面量类型

实现一个将字符串首字母大写的类型

// 要求实现 Capitalize
type Capitalize<S extends string> = ?;

// 测试
type A = Capitalize<'hello'>; // 'Hello'
type B = Capitalize<'world'>; // 'World'

// 答案
type Capitalize<S extends string> = S extends `${
     
     infer First}${
     
     infer Rest}`
  ? `${
     
     Uppercase<First>}${
     
     Rest}`
  : S;

// 进阶:实现驼峰命名转换
type CamelCase<S extends string> = S extends `${
     
     infer Head}_${
     
     infer Tail}`
  ? `${
     
     Head}${
     
     Capitalize<CamelCase<Tail>>}`
  : S;

type C = CamelCase<'user_name'>; // 'userName'
type D = CamelCase<'get_user_by_id'>; // 'getUserById'

React + TypeScript

题目 11:React 组件类型

定义一个 Button 组件的 Props 类型

// 要求:
// 1. 支持所有原生 button 属性
// 2. 添加自定义 loading 属性
// 3. children 必填

// 答案
import React from 'react';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
   
   
  loading?: boolean;
  children: React.ReactNode;
}

const Button: React.FC<ButtonProps> = ({
   
    
  loading, 
  children, 
  disabled,
  ...rest 
}) => {
   
   
  return (
    <button disabled={
   
   disabled || loading} {
   
   ...rest}>
      {
   
   loading ? 'Loading...' : children}
    </button>
  );
};

// 使用
<Button onClick={
   
   () => {
   
   }} loading={
   
   true}>
  Click me
</Button>

题目 12:useState 类型推断

问:以下代码有什么问题?如何修复?

// 问题代码
function UserProfile() {
   
   
  const [user, setUser] = useState(null);

  useEffect(() => {
   
   
    fetchUser().then((data) => {
   
   
      setUser(data); // data 可能是 User 类型
    });
  }, []);

  return <div>{
   
   user.name}</div>; // 错误:user 可能为 null
}

// 答案 1:使用类型断言
interface User {
   
   
  name: string;
  age: number;
}

const [user, setUser] = useState<User | null>(null);

return <div>{
   
   user?.name}</div>; // 使用可选链

// 答案 2:使用默认值
const [user, setUser] = useState<User>({
   
   
  name: '',
  age: 0,
});

// 答案 3:使用类型守卫
if (!user) return <div>Loading...</div>;
return <div>{
   
   user.name}</div>;

题目 13:useRef 类型

实现一个自动聚焦的输入框组件

// 答案
import React, {
   
    useRef, useEffect } from 'react';

const AutoFocusInput: React.FC = () => {
   
   
  // 方法 1:使用泛型
  const inputRef = useRef<HTMLInputElement>(null);

  // 方法 2:使用类型断言
  // const inputRef = useRef<HTMLInputElement>(null!);

  useEffect(() => {
   
   
    // null 检查
    if (inputRef.current) {
   
   
      inputRef.current.focus();
    }

    // 或使用可选链
    inputRef.current?.focus();
  }, []);

  return <input ref={
   
   inputRef} type="text" />;
};

// 进阶:转发 ref
interface InputProps {
   
   
  placeholder?: string;
}

const ForwardedInput = React.forwardRef<HTMLInputElement, InputProps>(
  ({
   
    placeholder }, ref) => {
   
   
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值