Skip to content

Latest commit

 

History

History
157 lines (123 loc) · 6.87 KB

avoid-aliasing.md

File metadata and controls

157 lines (123 loc) · 6.87 KB

Item 23: Be Consistent in Your Use of Aliases

Things to Remember

  • Aliasing can prevent TypeScript from narrowing types. If you create an alias for a variable, use it consistently.
  • Be aware of how function calls can invalidate type refinements on properties. Trust refinements on local variables more than on properties.

Code Samples

const place = {name: 'New York', latLng: [41.6868, -74.2692]};
const loc = place.latLng;

💻 playground


interface Coordinate {
  x: number;
  y: number;
}

interface BoundingBox {
  x: [number, number];
  y: [number, number];
}

interface Polygon {
  exterior: Coordinate[];
  holes: Coordinate[][];
  bbox?: BoundingBox;
}

💻 playground


function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
  if (polygon.bbox) {
    if (pt.x < polygon.bbox.x[0] || pt.x > polygon.bbox.x[1] ||
        pt.y < polygon.bbox.y[0] || pt.y > polygon.bbox.y[1]) {
      return false;
    }
  }

  // ... more complex check
}

💻 playground


function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
  const box = polygon.bbox;
  if (polygon.bbox) {
    if (pt.x < box.x[0] || pt.x > box.x[1] ||
        //     ~~~                ~~~  'box' is possibly 'undefined'
        pt.y < box.y[0] || pt.y > box.y[1]) {
        //     ~~~                ~~~  'box' is possibly 'undefined'
      return false;
    }
  }
  // ...
}

💻 playground


function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
  polygon.bbox
  //      ^? (property) Polygon.bbox?: BoundingBox | undefined
  const box = polygon.bbox;
  //    ^? const box: BoundingBox | undefined
  if (polygon.bbox) {
    console.log(polygon.bbox);
    //                  ^? (property) Polygon.bbox?: BoundingBox
    console.log(box);
    //          ^? const box: BoundingBox | undefined
  }
}

💻 playground


function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
  const box = polygon.bbox;
  if (box) {
    if (pt.x < box.x[0] || pt.x > box.x[1] ||
        pt.y < box.y[0] || pt.y > box.y[1]) {  // OK
      return false;
    }
  }
  // ...
}

💻 playground


function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
  const {bbox} = polygon;
  if (bbox) {
    const {x, y} = bbox;
    if (pt.x < x[0] || pt.x > x[1] || pt.y < y[0] || pt.y > y[1]) {
      return false;
    }
  }
  // ...
}

💻 playground


const {bbox} = polygon;
if (!bbox) {
  calculatePolygonBbox(polygon);  // Fills in polygon.bbox
  // Now polygon.bbox and bbox refer to different values!
}

💻 playground


function expandABit(p: Polygon) { /* ... */ }

polygon.bbox
//      ^? (property) Polygon.bbox?: BoundingBox | undefined
if (polygon.bbox) {
  polygon.bbox
  //      ^? (property) Polygon.bbox?: BoundingBox
  expandABit(polygon);
  polygon.bbox
  //      ^? (property) Polygon.bbox?: BoundingBox
}

💻 playground