Skip to content

Item 42: Avoid Types Based on Anecdotal Data

要点

  • Avoid writing types by hand based on data that you've seen. It's easy to misunderstand a schema or get nullability wrong.
  • Prefer types sourced from official clients or the community. If these don't exist, generate TypeScript types from schemas.
  • 避免根据你所看到的数据手动编写类型。误解 schema 或错误处理 nullability 是很容易的。
  • 优先使用官方客户端或社区提供的类型。如果没有这些,考虑从 schema 生成 TypeScript 类型。

正文

ts
function calculateBoundingBox(f: GeoJSONFeature): BoundingBox | null {
  let box: BoundingBox | null = null

  const helper = (coords: any[]) => {
    // ...
  }

  const { geometry } = f
  if (geometry) {
    helper(geometry.coordinates)
  }

  return box
}

💻 playground


ts
interface GeoJSONFeature {
  type: 'Feature'
  geometry: GeoJSONGeometry | null
  properties: unknown
}
interface GeoJSONGeometry {
  type: 'Point' | 'LineString' | 'Polygon' | 'MultiPolygon'
  coordinates: number[] | number[][] | number[][][] | number[][][][]
}

💻 playground


ts
import { Feature } from 'geojson'

function calculateBoundingBox(f: Feature): BoundingBox | null {
  let box: BoundingBox | null = null

  const helper = (coords: any[]) => {
    // ...
  }

  const { geometry } = f
  if (geometry) {
    helper(geometry.coordinates)
    //              ~~~~~~~~~~~
    //   Property 'coordinates' does not exist on type 'Geometry'
    //     Property 'coordinates' does not exist on type 'GeometryCollection'
  }

  return box
}

💻 playground


ts
const { geometry } = f
if (geometry) {
  if (geometry.type === 'GeometryCollection') {
    throw new Error('GeometryCollections are not supported.')
  }
  helper(geometry.coordinates) // OK
}

💻 playground


ts
const geometryHelper = (g: Geometry) => {
  if (g.type === 'GeometryCollection') {
    g.geometries.forEach(geometryHelper)
  } else {
    helper(g.coordinates) // OK
  }
}

const { geometry } = f
if (geometry) {
  geometryHelper(geometry)
}

💻 playground

Released under the MIT License.