# 27133-Square

# 题目描述

给定一个数字 N,返回 N * N。要求支持负数,且能处理至少到 Square<101> = 10201

type R1 = Square<3>; // 9
type R2 = Square<20>; // 400
type R3 = Square<-5>; // 25
type R4 = Square<101>; // 10201

# 分析

本题看着像普通乘法,实则 非常棘手

  • 类型层做乘法通常借元组长度 (加减乘除);
  • 101 * 101 = 10201,要造一个长度 10201 的元组,远超 TS 默认 1000 层的尾递归限制。

所以必须想办法降低递归深度

  • 一种思路是每轮 push 多个元素(比如 10 个),把深度降为 N / 10
  • 结合 A * B 可以拆成 "A 的 B 份拼接",每份由 BuildTuple<A> 提供,整体深度约为 B + BuildTuple<A> 的深度。

再叠加 负数:先把符号剥掉,平方完是正数,平方本来就与符号无关。

# 题解

// 去掉负号
type Abs<N extends number> = `${N}` extends `-${infer R extends number}`
  ? R
  : N;

// 每轮 push 10 个,把构造 N 长度元组的深度降到 ~N/10
type BuildFast<N extends number, R extends any[] = []> = R['length'] extends N
  ? R
  : [
      ...R,
      any,
      any,
      any,
      any,
      any,
      any,
      any,
      any,
      any,
      any,
    ]['length'] extends infer L
  ? L extends number
    ? L extends N
      ? [...R, any, any, any, any, any, any, any, any, any, any]
      : L extends infer _ // always true, for nicer format
      ? BuildFast<N, [...R, any, any, any, any, any, any, any, any, any, any]>
      : never
    : never
  : never;

// 退化版:慢但对边界更稳
type BuildSlow<N extends number, R extends any[] = []> = R['length'] extends N
  ? R
  : BuildSlow<N, [...R, any]>;

// A * B:把 B 个 BuildTuple<A> 拼起来
type Mul<A extends number, B extends number, R extends any[] = []> = B extends 0
  ? R['length']
  : Mul<A, Dec<B>, [...R, ...BuildSlow<A>]>;

type Dec<N extends number> = BuildSlow<N> extends [any, ...infer R]
  ? R['length']
  : 0;

type Square<N extends number> = Mul<Abs<N>, Abs<N>>;

几点说明:

  • Abs<N> 通过模板字符串剥掉前导 -,处理负数输入。
  • 真实提交时可把 BuildSlow 替换成 BuildFast(每轮 push 10 个);两者逻辑等价,只是后者深度更浅。
  • Mul 是教科书式的"加 B 次 A"。

# ⚠️ 已知局限

本题上游测试集要求 Square<101> = 10201 通过。但 TS 类型系统对元组字面量的大小有硬性上限(约 10000),而 Mul<A, B> 需要物化一个长度 A * B 的元组——101 * 101 = 10201 超出,会触发 TS2799: Type produces a tuple type that is too large to represent

本文给出的"元组长度法"最高只能稳跑到 Square<100>。要让 Square<101> 及以上跑通,必须改用字符串竖式乘法:把数字拆成字符数组,按位相乘 + 进位再拼回字符串,全程避免物化大元组。这是另一整套实现,本文不展开。

# 验证

type R1 = Square<0>; // 0
type R2 = Square<3>; // 9
type R3 = Square<20>; // 400
type R4 = Square<-5>; // 25
type R5 = Square<-31>; // 961

# 知识点

  • 模板字符串剥符号 ${N} extends -${infer R extends number} —— TS 4.8+ 支持 infer X extends Y 语法。
  • 类型层数值运算的深度限制与优化:见 加减乘除 以及 递归深度
  • 大数字的终极方案是改为字符串竖式乘法(数字逐位相乘 + 进位累加),本文不展开。
Last Updated: 2026/4/19 01:03:47