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

如何实现Geometry类型的通用Type Guard解决类型收窄问题?

通用Geometry类型守卫的正确实现方案

一、基础类型定义

我们工作中使用以下TypeScript类型作为Geometry的基础:

export type GeoJSON = Geometry | Feature;

export type GeoJsonTypes = GeoJSON['type'];

export interface GeoJsonObject { type: GeoJsonTypes; }

export interface Point extends GeoJsonObject {
   type: 'Point';
   coordinates: number[];
 }

export interface MultiPoint extends GeoJsonObject {
   type: "MultiPoint",
   coordinates: number[][];
 }

export type Geometry =
 | Point
 | MultiPoint

export interface Feature<G extends Geometry = Geometry>
  extends GeoJsonObject {
  type: 'Feature';
  geometry: G;
}

二、现有单独类型守卫方案

目前我们为每个Geometry类型单独编写Type Guard,例如判断Point的守卫:

export const isPointGeometry = (g: Geometry): g is Point => {
  return (g as Point).type === 'Point';
};

这种方案虽可行,但新增Geometry类型时需重复编写类似代码,效率较低。

三、无效的通用类型守卫尝试

尝试编写通用Type Guard,但实现无效,无法正确收窄类型:

export function isGeometry<T extends Geometry, G extends GeoJsonObject['type']>(feature: T, geometry: G): feature is T {
  return feature && feature.type === geometry;
}

在如下函数中使用时,f.geometry仍为Point | MultiPoint联合类型,无法正确获取Point类型的coordinates:

export function coordinatesFor(f: Feature<Point | MultiPoint>) {
  if (isGeometry(f.geometry, 'Point')) {
   return f.geometry.coordinates ?? []; // 此处f.geometry未被收窄为Point
  }
  return [];
 }

四、正确的通用类型守卫实现

核心是建立GeoJSON类型字符串与具体Geometry类型的映射,让TypeScript能根据传入的类型字符串推断出对应的具体类型:

步骤1:定义类型映射表

先创建一个映射类型,把每个GeoJSON类型字符串关联到对应的Geometry接口:

// 建立类型字符串到具体Geometry类型的映射
type GeometryTypeMap = {
  'Point': Point;
  'MultiPoint': MultiPoint;
};

步骤2:实现通用类型守卫

利用这个映射表编写通用守卫,让泛型参数关联到映射表的键,从而实现精准的类型推断:

export function isGeometry<T extends keyof GeometryTypeMap>(
  geometry: Geometry,
  type: T
): geometry is GeometryTypeMap[T] {
  return geometry.type === type;
}

步骤3:验证使用效果

现在在函数中使用这个通用守卫,TypeScript会正确收窄类型:

export function coordinatesFor(f: Feature<Point | MultiPoint>) {
  if (isGeometry(f.geometry, 'Point')) {
    // f.geometry已被收窄为Point,coordinates为number[]类型
    return f.geometry.coordinates ?? [];
  }
  // 此处f.geometry自动收窄为MultiPoint
  return f.geometry.coordinates.flat() ?? [];
}

优势说明

  • 无需重复编写单个类型守卫,新增Geometry类型时,只需在GeometryTypeMap中添加对应键值对即可
  • 类型推断精准,完全符合TypeScript的类型收窄规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 05:43:24