You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript移除any类型遇阻:MSGraph API相关代码类型规范求助

移除TypeScript代码中的any类型并适配MS Graph API类型

先统一定义核心类型(可新建types.ts文件存放),明确所有数据结构:

// types.ts
export interface BirthdayPerson {
  id: string;
  displayName: string;
  birthday: string; // MS Graph返回的生日为ISO格式字符串,如"1990-05-15"
  picture?: string; // 头像的Blob URL
}

// MS Graph用户列表返回的单用户结构(仅保留业务所需字段)
export interface GraphUser {
  id: string;
  displayName: string;
}

// MS Graph分页响应通用结构
export interface GraphPaginatedResponse<T> {
  value: T[];
  '@odata.nextLink'?: string;
}

// 获取用户生日的接口返回结构
export interface GraphBirthdayResponse {
  value: string;
}

改造graph.ts

将分页请求函数改为泛型,彻底移除any,明确返回类型:

// graph.ts
async function callMsGraph(accessToken: string, endpoint: string): Promise<Response> {
  const headers = new Headers();
  const bearer = `Bearer ${accessToken}`;

  headers.append('Authorization', bearer);

  const options = {
    method: 'GET',
    headers,
  };
  try {
    return fetch(endpoint, options);
  } catch (error) {
    console.error(error);
    throw error;
  }
}

export const callMsGraphWithoutPagination = async <T>(
  accessToken: string,
  url: string,
  dataToReturn: T[] = []
): Promise<T[]> => {
  try {
    const data = await callMsGraph(accessToken, url);
    const dataJson = await data.json() as GraphPaginatedResponse<T>;
    const newData = dataToReturn.concat(dataJson.value);
    if (dataJson['@odata.nextLink']) {
      const NEXT_URL = dataJson['@odata.nextLink'].split('/v1.0')[1];
      return await callMsGraphWithoutPagination(
        accessToken,
        `${process.env.REACT_APP_GRAPH_URL}${NEXT_URL}`,
        newData
      );
    }
    return newData;
  } catch (error) {
    console.error(error);
    throw error;
  }
};

export default callMsGraph;

改造useUsers.tsx

明确所有变量类型,替换掉所有any:

// useUsers.tsx
import { GraphUser, GraphBirthdayResponse, BirthdayPerson } from './types';

export const useUsers = () => {
  const token = useToken();
  const [users, setUsers] = React.useState<BirthdayPerson[]>([]);

  React.useEffect(() => {
    if (!token) return;

    callMsGraphWithoutPagination<GraphUser>(token, graphConfig.usersEndpoint)
      .then(async (usersData) => {
        const processedData = await Promise.all(
          usersData.map(async (user) => {
            // 获取用户生日
            const birthdayRes = await callMsGraph(token, graphConfig.userBirthdayEndpoint(user.id));
            const birthdayJson = await birthdayRes.json() as GraphBirthdayResponse;
            // 获取用户头像
            const imageRes = await callMsGraph(token, graphConfig.userPhotoEndpoint(user.id));
            const blob = await imageRes.blob();

            const returnElement: BirthdayPerson = {
              displayName: user.displayName,
              birthday: birthdayJson.value,
              id: user.id,
            };

            if (blob) {
              window.URL = window.URL || window.webkitURL;
              returnElement.picture = window.URL.createObjectURL(blob);
            }

            return returnElement;
          })
        );

        setUsers(processedData);
      })
      .catch(error => console.error('获取用户数据失败:', error));
  }, [token]);

  return users;
};

改造helpers.ts

移除所有any,明确参数和返回类型:

// helpers.ts
import { BirthdayPerson } from './types';

interface IUpdateData {
  slideCount: number;
}

const sortAndFilterBirthdays = (people: BirthdayPerson[], daysToGet: number): BirthdayPerson[] =>
  people
    .sort((firstEl, secondEl) => sortDate(firstEl.birthday, secondEl.birthday))
    .filter(({ birthday }) => filterByAmountOfDays({ date: birthday, daysAfter: daysToGet }));

const getBirthdays = (people: BirthdayPerson[], daysToGet: number): BirthdayPerson[] => {
  const validBirthdays = people.filter((element) => {
    const year = moment(element.birthday).year();
    return year !== 0;
  });
  const result = sortAndFilterBirthdays(validBirthdays, daysToGet);

  if (result.length > 1 && daysToGet <= 30) {
    return result;
  }

  const fallbackResult = validBirthdays
    .sort((firstEl, secondEl) => sortDate(firstEl.birthday, secondEl.birthday))
    .filter((person) => {
      const currentYear = moment().year();
      const date = moment(person.birthday, DATE_FORMAT).set('years', currentYear);
      return moment().diff(date, 'days') <= 0;
    });

  return [...fallbackResult, ...validBirthdays].slice(0, 2);
};

关键注意事项

  • 泛型复用:callMsGraphWithoutPagination改为泛型后,可适配不同MS Graph接口的返回类型,避免any带来的类型模糊。
  • 类型断言:调用data.json()时用as断言为对应接口类型,让TypeScript明确数据结构。
  • 生日类型对齐:MS Graph返回的生日是字符串格式,需与BirthdayPerson的birthday类型保持一致;若需Date类型,可在处理时转换(如new Date(birthdayJson.value))。
  • 冗余代码清理:原代码中setUsers([].concat(...processedData))属于冗余操作,直接赋值processedData即可。

内容的提问来源于stack exchange,提问作者Semedmar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:02:12