Home > Mobile >  typescript object possibly undefined no matter what I tried
typescript object possibly undefined no matter what I tried

Time:10-14

I am using canvas to capture the cropped image. here is the function

export const getCroppedImg = (
  image: HTMLImageElement,
  crop: Crop,
  fileName: string
): Promise<Blob> => {
  let canvas: HTMLCanvasElement;
  let ctx: CanvasRenderingContext2D;
  // I m using next.js
  if (typeof window !== "undefined") {
    if (crop) {
      canvas = document.createElement("canvas");
      const scaleX = image.naturalWidth / image.width;
      const scaleY = image.naturalHeight / image.height;
      canvas.width  =crop.width ? crop.width * scaleX : undefined;
      canvas.height =crop.height &&  crop.height * scaleY;
      ctx = canvas.getContext("2d") as CanvasRenderingContext2D;

      ctx.drawImage(
        image,
        crop.x * scaleX,
        crop.y * scaleY,
        crop.width * scaleX,
        crop.height * scaleY,
        0,
        0,
        crop.width * scaleX,
        crop.height * scaleY
      );
    }
  }

crop.x, crop.y, crop.width crop.height causing ts error "Object is possibly 'undefined' ". I wrapped entire logic with if(crop), i tried two diffent approaches

      canvas.width  =crop.width ? crop.width * scaleX : undefined;
      canvas.height =crop.height &&  crop.height * scaleY;

"canvas.width" and "canvas.height" warns that

"Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.ts(2322)

Here is the Crop:

import { Crop } from "react-image-crop";

interface Crop {
        aspect?: number;
        x?: number;
        y?: number;
        width?: number;
        height?: number;
        unit?: 'px' | '%';
    }
    
                

CodePudding user response:

Take out the existing crop.width and crop.height into their own variables before checking them.

You also can't assign undefined to a canvas.width, or use && to conditionally assign a value to the height - use if instead.

It doesn't look like proceeding with any of the logic makes sense if any of the crop properties are undefined (you wouldn't be able to draw the canvas or use drawImage properly), so throw an error or return early in such cases.

You also aren't returning a Promise, so remove the Promise<Blob> type.

export const getCroppedImg = (
    image: HTMLImageElement,
    crop: Crop,
) => {
    const { width, height, x, y } = crop;
    if (typeof window === "undefined" || !width || !height || !x || !y) {
        // Proceeding further would make no sense;
        // can't adjust canvas, or draw the image
        // return here, or throw an error or something
        throw new Error('Bad argument');
    }
    const canvas = document.createElement("canvas");
    const scaleX = image.naturalWidth / image.width;
    const scaleY = image.naturalHeight / image.height;

    canvas.width = width * scaleX;
    canvas.height = height * scaleY;
    const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;

    ctx.drawImage(
        image,
        x * scaleX,
        y * scaleY,
        width * scaleX,
        height * scaleY,
        0,
        0,
        width * scaleX,
        height * scaleY
    );
}

CodePudding user response:

You are saying in this line that canvas.width could be undefined:

canvas.width  =crop.width ? crop.width * scaleX : undefined;

so you can re work the logic so that is not the case. That being said, sometimes you will know more than the TypeScript compiler so if you know that the value will never be undefined when you need to access it, you can assert the value.

canvas.width as number

CodePudding user response:

Why do you use optional fields on Crop interface?

Have you tried this?:

interface Crop {
    aspect: number;
    x: number;
    y: number;
    width: number;
    height: number;
    unit: 'px' | '%';
}
  • Related