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

TypeScript:创建以维度为泛型的坐标类型及类型适配

TypeScript 泛型实战:特定长度数组的接口与函数适配

需求与初始代码

我需要定义几种特定长度的数组类型,包含固定长度数组和最小长度数组,初始代码如下:

interface FixedLengthArray<T, L extends number> extends ReadonlyArray<T> {
  0: T;
  length: L;
}
type Coordinates2D = FixedLengthArray<number, 2>;
type Coordinates3D = FixedLengthArray<number, 3>

type CoordinatesMin2D = {
  0: number
  1: number
} & ReadonlyArray<number>

type CoordinatesMin3D = {
  0: number
  1: number
  2: number
} & ReadonlyArray<number>

type Coordinates = ReadonlyArray<number>; // 修正原代码语法错误

接下来要解决两个核心问题:

  1. 定义能兼容上述所有坐标类型的KeyAndCoords接口;
  2. 实现center2DCoordinates函数,仅允许传入包含至少2维坐标的KeyAndCoords(即Coordinates2D/Coordinates3D/CoordinatesMin2D/CoordinatesMin3D,排除普通Coordinates类型,因为它可能长度不足2)。

补充规则:

  • 普通Coordinates为任意长度数组,不能直接传入center2DCoordinates,但getMaxOfCoordinates这类函数需要兼容所有坐标类型;
  • 以下传入center2DCoordinates的场景需符合预期:
    x: Coordinates = [1]  // 失败(长度不足2)
    x: Coordinates = [1, 1]  // 成功(长度为2)
    x: Coordinates = [1, 1, 1]  // 成功(长度≥2)
    x: Coordinates2D = [1, 1]  // 成功
    x: Coordinates3D = [1, 1, 1]  // 成功
    x: CoordinatesMin2D = [1, 1, 1]  // 成功
    
    center2DCoordinates([{ key: "test", coordinates: x }])
    

解决方案

1. 优化最小长度数组的泛型定义

封装通用的最小长度数组泛型,避免重复定义冗余类型:

type MinLengthArray<T, L extends number> = L extends 0
  ? ReadonlyArray<T>
  : { [K in 0..L-1]: T } & ReadonlyArray<T>;

// 用泛型重新定义最小长度坐标类型
type CoordinatesMin2D = MinLengthArray<number, 2>;
type CoordinatesMin3D = MinLengthArray<number, 3>;

2. 定义泛型版KeyAndCoords接口

让接口支持泛型参数,兼容所有坐标类型:

interface KeyAndCoords<C extends ReadonlyArray<number>> {
  key: string;
  coordinates: C;
}

3. 实现center2DCoordinates的类型约束

通过条件类型判断坐标是否满足至少2个元素,同时用泛型约束函数参数:

// 类型守卫:判断坐标类型是否至少包含2个元素
type IsAtLeast2D<C extends ReadonlyArray<number>> = 
  C extends { length: infer L } 
    ? L extends number 
      ? L extends 0 | 1 
        ? false 
        : true 
      : true 
    : C extends { 0: number; 1: number } 
      ? true 
      : false;

// 函数仅接收满足IsAtLeast2D的坐标类型
const center2DCoordinates = <C extends ReadonlyArray<number>>(
  keyAndCoords: KeyAndCoords<C>[]
): KeyAndCoords<C> => {
  // 业务逻辑示例:计算中心坐标
  const totalX = keyAndCoords.reduce((sum, item) => sum + item.coordinates[0], 0);
  const totalY = keyAndCoords.reduce((sum, item) => sum + item.coordinates[1], 0);
  return {
    key: "center",
    coordinates: [totalX / keyAndCoords.length, totalY / keyAndCoords.length] as C
  };
};

// 兼容所有坐标类型的示例函数
const getMaxOfCoordinates = <C extends ReadonlyArray<number>>(
  keyAndCoords: KeyAndCoords<C>[]
): number => {
  return Math.max(...keyAndCoords.flatMap(item => item.coordinates));
};

验证传入场景

测试各种传入情况,符合预期约束:

// 失败:Coordinates长度为1,不满足要求
const invalidCoord: Coordinates = [1];
center2DCoordinates([{ key: "test", coordinates: invalidCoord }]); // 类型错误

// 成功:Coordinates长度为2
const validCoord2: Coordinates = [1, 1];
center2DCoordinates([{ key: "test", coordinates: validCoord2 }]); // 正常通过

// 成功:Coordinates长度为3
const validCoord3: Coordinates = [1, 1, 1];
center2DCoordinates([{ key: "test", coordinates: validCoord3 }]); // 正常通过

// 成功:固定长度2D坐标
const coord2D: Coordinates2D = [1, 1];
center2DCoordinates([{ key: "test", coordinates: coord2D }]); // 正常通过

// 成功:固定长度3D坐标
const coord3D: Coordinates3D = [1, 1, 1];
center2DCoordinates([{ key: "test", coordinates: coord3D }]); // 正常通过

// 成功:最小长度2D坐标
const minCoord2D: CoordinatesMin2D = [1, 1, 1];
center2DCoordinates([{ key: "test", coordinates: minCoord2D }]); // 正常通过

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 12:39:22