返回

TS 体操面试题揭秘:如何用类型限制日期格式

前端

掌握字节跳动面试中不可或缺的日期格式化技巧

在字节跳动备受瞩目的面试过程中,算法题和数据结构题往往占据着显赫地位,然而,一道看似简单的日期格式化题目却令无数面试者眼前一亮。

问题的本质:简单中的复杂

乍一看,实现一个 FormatDate 类型似乎轻而易举,但这道题却考察了面试者对类型系统、正则表达式、日期格式化和解析等多方面的深刻理解。

深入分析:从格式定义到数据转换

首先,我们必须定义日期格式,而这涉及到正则表达式或更严格类型约束的使用。其次,我们需要将字符串解析成日期对象,这就需要熟练掌握日期格式化和解析的技巧。最后,我们必须将日期对象格式化为字符串,这与解析相反,同样需要考虑如何以指定格式输出日期。

解决方案:类型化与函数式编程的融合

为了解决这个问题,我们可以使用类型化和函数式编程的组合。首先,我们可以定义一个 DateType 类型来表示日期格式,然后实现 FormatDate 和 UnformatDate 类型,用于分别将字符串解析成日期对象和将日期对象格式化为字符串。

代码示例:简洁而高效

以下代码展示了如何实现 FormatDate 和 UnformatDate 函数:

// 定义日期格式类型
export type DateType = "yyyy-MM-dd" | "yyyy/MM/dd" | "yyyy.MM.dd";

// 将字符串解析成日期对象
export type FormatDate<S extends string, DT extends DateType> = (date: S) => Date | null;

// 将日期对象格式化为字符串
export type UnformatDate<DT extends DateType> = (date: Date) => string;

// 具体实现
const formatDate: FormatDate<string, "yyyy-MM-dd"> = (date) => {
  // 将字符串拆分为年月日
  const parts = date.split("-");
  
  // 检查格式和有效性
  if (parts.length !== 3) {
    return null;
  }
  const year = parseInt(parts[0]);
  const month = parseInt(parts[1]);
  const day = parseInt(parts[2]);
  if (year < 1900 || year > 2100 || month < 1 || month > 12 || day < 1 || day > 31) {
    return null;
  }
  
  // 返回 Date 对象
  return new Date(year, month - 1, day);
};

const unformatDate: UnformatDate<"yyyy-MM-dd"> = (date) => {
  // 使用toISOString获取日期字符串并截取前 10 位
  return date.toISOString().slice(0, 10);
};

常见问题解答

Q1:为什么使用类型化?

A:类型化有助于定义日期格式,确保输入的字符串符合指定的格式。

Q2:正则表达式是否也可以用于日期格式化?

A:可以,但使用更严格的类型约束可以避免正则表达式可能带来的错误和不确定性。

Q3:为什么需要函数式编程?

A:函数式编程可以使代码更简洁、可维护,并且便于测试。

Q4:这道题在实际工作中有什么应用?

A:日期格式化在各种实际应用中都至关重要,例如处理用户输入、生成报表和存储日期数据。

Q5:如何提高日期格式化技能?

A:多练习,熟悉各种日期格式,并使用类型化和函数式编程等技术来编写健壮、高效的代码。

结论

这道字节跳动面试题看似简单,但它却巧妙地考验了面试者的多方面技能。掌握日期格式化的技巧对于前端工程师来说至关重要,因为它在实际工作中无处不在。通过认真研究这道题及其解决方案,你将提升自己的前端技能,为在字节跳动等科技巨头面试中脱颖而出做好准备。