为何drawImage无法接收参数?napi-rs/canvas类型错误排查
问题场景
执行这段代码时出现TypeScript错误:
context.drawImage(img, img.width, img.height)
错误提示
This expression is not callable.
Each member of the union type '{ (image: CanvasImageSource, dx: number, dy: number): void; (image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void; (image: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; } | { ...; }' has signatures, but none of those signatures are compatible with each other.ts(2349)
对应的drawImage类型定义:
(property) drawImage: { (image: Image | Canvas, dx: number, dy: number): void; (image: Image | Canvas, dx: number, dy: number, dw: number, dh: number): void; (image: Image | Canvas, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; } | { ...; }
相关代码
当前函数的参数签名:
const drawFrame = ( context: CanvasRenderingContext2D | SKRSContext2D, positions: typeof startPositions, title: string, text: string, img: Image, locale?: string ) => {
使用@napi-rs/canvas库的导入语句:
import { createCanvas, GlobalFonts, Image, loadImage, SKRSContext2D, } from '@napi-rs/canvas'
错误原因
核心问题是context是浏览器原生CanvasRenderingContext2D和**@napi-rs/canvas的SKRSContext2D**的联合类型,两者的drawImage方法签名不兼容:
- 原生
CanvasRenderingContext2D.drawImage的第一个参数接受CanvasImageSource(包含Image、Canvas、Video等多种类型) SKRSContext2D.drawImage的第一个参数只限定为Image | Canvas- TypeScript对联合类型的方法调用会严格校验所有分支的签名兼容性,哪怕你传入的
img是符合要求的Image类型,也无法通过联合类型的签名校验
解决办法
1. 类型收窄
在调用drawImage前,把context断言为具体类型:
// 直接断言为其中一种类型 (context as SKRSContext2D).drawImage(img, img.width, img.height); // 或者做类型判断后断言 if ('fillText' in context) { // 用特征方法区分两种上下文 (context as CanvasRenderingContext2D).drawImage(img, img.width, img.height); } else { (context as SKRSContext2D).drawImage(img, img.width, img.height); }
2. 统一参数类型
如果你的代码只在Node环境用@napi-rs/canvas,直接把context的类型改成SKRSContext2D就行:
const drawFrame = ( context: SKRSContext2D, // 移除CanvasRenderingContext2D positions: typeof startPositions, title: string, text: string, img: Image, locale?: string ) => { context.drawImage(img, img.width, img.height); // 直接调用无报错 }
3. 写兼容包装函数
封装一个适配两种上下文的函数,跳过类型校验:
function drawImage( ctx: CanvasRenderingContext2D | SKRSContext2D, img: Image, ...args: number[] ) { (ctx as any).drawImage(img, ...args); } // 使用时直接调用 drawImage(context, img, img.width, img.height);
内容的提问来源于stack exchange,提问作者Alma

