【问题标题】:Typescript type a is not assignable to type b打字稿类型 a 不可分配给类型 b
【发布时间】:2019-09-25 22:59:33
【问题描述】:

故事

我正在使用konva library 和 Typescript,它是 HTML5 Canvas JavaScript 框架。

这是一个简单的教程代码,我将其从 javascript 更改为 typescript。

import Konva from "konva";

const stage = new Konva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight
});

const layer = new Konva.Layer();
stage.add(layer);

const box = new Konva.Rect({
  x: 50,
  y: 50,
  width: 100,
  height: 50,
  fill: '#00D2FF',
  stroke: 'black',
  strockWidth: 4,
  draggable: true
});

layer.add(box);

但我的 Visual Studio 代码显示如下错误消息。

Argument of type 'Rect' is not assignable to parameter of type 'Group | Shape<ShapeConfig>'.
  Type 'Rect' is not assignable to type 'Shape<ShapeConfig>'.
    Types of property 'hitFunc' are incompatible.
      Type 'GetSet<(ctx: Context, shape: Rect) => void, Rect>' is not assignable to type 'GetSet<(ctx: Context, shape: Shape<ShapeConfig>) => void, Shape<ShapeConfig>>'.
        Type '(ctx: Context, shape: Rect) => void' is not assignable to type '(ctx: Context, shape: Shape<ShapeConfig>) => void'.
          Types of parameters 'shape' and 'shape' are incompatible.
            Type 'Shape<ShapeConfig>' is missing the following properties from type 'Rect': _sceneFunc, cornerRadiusts(2345)

Shape 类在 Shape.d.ts 中,RectRect.d.ts 中。 我可以看到Rect 扩展了Shape!但 VSC 显示错误。

如果我将Rect.d.ts 中的两个属性添加到Shape 类中, 错误消失了

export declare class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<Config> {
    _sceneFunc(context: any): void; // this was in Rect class
    cornerRadius: GetSet<number, this>; // this was in Rect class
    ...
    ...

问题

我知道layer.add() 函数只接受Shape 类型。但如您所知,Typescript 允许像下面这样向下转换。

class Base {
  baseProperty: string = "aaaa";
}
class A extends Base {
  aProperty: number = 1;
}
var a: A = new A();
function test(arg: Base) {
  console.log(arg.baseProperty);
}
test(a); // => No Error

我不明白为什么 layer.add() 不能接受 Rect 类型,即使它扩展了 Shape 类型。我错过了什么?

我需要你的建议。 谢谢。

【问题讨论】:

  • 你试过 layer.add( box) 吗?
  • @CharybdeBE 错误:Conversion of type 'Rect' to type 'Shape&lt;ShapeConfig&gt;' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

标签: typescript konvajs


【解决方案1】:

不幸的是,库的定义显然没有使用strictFunctionTypes 进行测试。

如果未激活此选项,则函数以双变量方式关联,但在strictFunctionTypes 下,函数在参数类型方面以逆变方式关联。这意味着:

class Animal { private x:undefined }
class Dog extends Animal { private d: undefined }

type EventHandler<E extends Animal> = (event: E) => void

let o: EventHandler<Animal> = (o: Dog) => { } // fails under strictFunctionTyes

您遇到的错误出现在hitFunc(如果在sceneFunc 上已修复),这些函数采用this 的第二个参数,实际上是Shape&lt;ShapeConfig&gt;。当我们尝试在Rect 中分配hitFunc 时,这会触发错误,该参数具有第二个参数,也键入为this,但实际上是Rect。您不能将具有派生参数类型的函数分配给可以接受任何基类型参数的函数签名。

有多种可能的解决方案:

  1. 使用类型断言

    layer.add(box as unknown as Shape<ShapeConfig>);
    
  2. 禁用 strictFunctionTypes(在 tsconfig 中使用 strictFunctionTypes: false 时错误消失)

  3. 提交拉取请求以明确键入以使hitFuncsceneFuncstrictFunctionTypes: true 下表现为双变量事件,如here 所述。在这种情况下,这将起作用并保留功能:

    export type ShapeConfigHanlder<TTarget> = {
        bivarianceHack(ctx: Context, shape: TTarget): void
    }['bivarianceHack']
    export interface Shape extends NodeConfig {
        ...
        hitFunc: GetSet<ShapeConfigHanlder<this>, this>;
        sceneFunc: GetSet<ShapeConfigHanlder<this>, this>;
    }
    

【讨论】:

  • @ByeonginYoon 你打算提交 PR 吗?如果你不这样做,我可能会这样做
  • 我很好,你可以!
猜你喜欢
  • 2021-08-25
  • 2021-10-11
  • 2020-06-29
  • 1970-01-01
  • 2022-08-14
  • 2016-10-25
  • 2019-07-29
  • 2018-02-02
  • 2021-06-17
相关资源
最近更新 更多