Skip to content

统一同类函数的返回类型

可预测性

就像与 API 调用相关的 Hook 一样,如果同类函数或 Hook 具有不同的返回类型,代码的一致性就会降低,同事阅读代码时会产生混乱。

📝 代码示例 1: useUser

以下 useUseruseServerTime Hook 都与 API 调用相关。

但是 useUser 返回的是 @tanstack/react-queryQuery 对象,而 useServerTime 则是获取服务器时间后仅返回数据本身 。

typescript
import { useQuery } from "@tanstack/react-query";

function useUser() {
  const query = useQuery({
    queryKey: ["user"],
    queryFn: fetchUser
  });

  return query;
}

function useServerTime() {
  const query = useQuery({
    queryKey: ["serverTime"],
    queryFn: fetchServerTime
  });

  return query.data;
}

👃 闻代码

可预测性

如果调用服务器 API 的 Hook 返回类型各不相同,则其他同事每次使用这些 Hook 时都需要查看并确认返回类型。如果返回的是 Query 对象,那么就需要从中提取出 data;如果仅返回数据本身,则可以直接使用返回值。

如果执行同一功能的代码不遵循一贯原则,则阅读和编写代码时会产生混乱。

✏️ 尝试改善

像下列代码一样,将调用服务器 API 的 Hook 一致地返回 Query 对象,可以提高团队成员对代码的可预测性。

typescript
import { useQuery } from "@tanstack/react-query";

function useUser() {
  const query = useQuery({
    queryKey: ["user"],
    queryFn: fetchUser
  });

  return query;
}

function useServerTime() {
  const query = useQuery({
    queryKey: ["serverTime"],
    queryFn: fetchServerTime
  });

  return query;
}

📝 代码示例 2: checkIsValid

下面 checkIsNameValidcheckIsAgeValid 都是用来检验姓名和年龄的有效性的函数。

typescript
/** 用户名必须少于20个字符。 */
function checkIsNameValid(name: string) {
  const isValid = name.length > 0 && name.length < 20;

  return isValid;
}

/** 用户的年龄必须是18岁至99岁之间的自然数。 */
function checkIsAgeValid(age: number) {
  if (!Number.isInteger(age)) {
    return {
      ok: false,
      reason: "年龄必须是整数。"
    };
  }

  if (age < 18) {
    return {
      ok: false,
      reason: "年龄必须年满18岁。"
    };
  }

  if (age > 99) {
    return {
      ok: false,
      reason: "年龄必须在99岁以下。"
    };
  }

  return { ok: true };
}

👃 闻代码

可预测性

如果有效性检查函数的返回值各不相同,则同事们在使用这些函数时每次都需要确认返回类型,这很容易造成混淆。

特别是在不使用诸如 严格布尔表达式 类似功能的情况下,这很可能成为代码中出错的源头。

typescript
// 这段代码验证姓名是否符合规则
if (checkIsNameValid(name)) {
  // ...
}

// 该函数只返回一个对象 { ok, ... },
// `if` 语句内的代码总是会被执行
if (checkIsAgeValid(age)) {
  // ...
}

✏️ 尝试改善

像下列代码一样,可将有效性检验函数始终返回一个 { ok, ... } 类型的对象。

typescript
/** 用户名必须少于20个字符。 */
function checkIsNameValid(name: string) {
  if (name.length === 0) {
    return {
      ok: false,
      reason: "姓名不允许为空值。"
    };
  }

  if (name.length >= 20) {
    return {
      ok: false,
      reason: "姓名不能超过20个字符。"
    };
  }

  return { ok: true };
}

/** 用户的年龄必须是18岁至99岁之间的自然数。 */
function checkIsAgeValid(age: number) {
  if (!Number.isInteger(age)) {
    return {
      ok: false,
      reason: "年龄必须是整数。"
    };
  }

  if (age < 18) {
    return {
      ok: false,
      reason: "年龄必须年满18岁。"
    };
  }

  if (age > 99) {
    return {
      ok: false,
      reason: "年龄必须在99岁以下。"
    };
  }

  return { ok: true };
}