reactjs useImmer with Image:类型“Element”不可分配给类型“WritableDraft< Element>”

ktca8awb  于 2023-08-04  发布在  React
关注(0)|答案(1)|浏览(162)

我正在尝试缓存图像,以便稍后使用drawImage在画布上渲染。
所以我定义了cache的类型:

type Cache = {
  image: Record<string, HTMLImageElement>,
};

const initialCache = {
  image: {},
};

字符串
在父组件中,我使用useImmer

function Component() {
  const [cache, setCache] = useImmer(initialCache);

  return <Child cache={cache} setCache={setCache} />
}


最后,在子组件中,我尝试使用async IIFE在useEffect中获取(或设置)它:

function Child(props: { cache: Cache, setCache: Updater<Cache> }) {
  useEffect(() => {
    (async () => {
      const imageKey = "forDemonstrationPurposes";
      const maybeImg = props.cache.image[imageKey];

      let img = maybeImg;

      if (!img) {
        img = new Image();

        img.src = "Some base64 string";

        props.setCache((d) => {
          d.image[imageKey] = img; // ERROR!
        });
      }
    })();
  }, []);

  // ...
}


在标记为ERROR!的地方,我得到了vscode:
Type 'Element' is not assignable to type 'WritableDraft<Element> | WritableDraft<ProcessingInstruction> | null'.
当浏览器用很长的错误消息向我尖叫时:

Type 'HTMLImageElement' is not assignable to type 'WritableDraft<HTMLImageElement>'.
  Types of property 'offsetParent' are incompatible.
    Type 'Element | null' is not assignable to type 'WritableDraft<Element> | null'.
      Type 'Element' is not assignable to type 'WritableDraft<Element>'.
        Types of property 'attributes' are incompatible.
          Type 'NamedNodeMap' is not assignable to type 'WritableDraft<NamedNodeMap>'.
            'number' index signatures are incompatible.
              Type 'Attr' is not assignable to type 'WritableDraft<Attr>'.
                The types of 'ownerDocument.anchors' are incompatible between these types.
                  Type 'HTMLCollectionOf<HTMLAnchorElement>' is not assignable to type 'WritableDraft<HTMLCollectionOf<HTMLAnchorElement>>'.
                    'number' index signatures are incompatible.
                      Type 'HTMLAnchorElement' is not assignable to type 'WritableDraft<HTMLAnchorElement>'.
                        Types of property 'shadowRoot' are incompatible.
                          Type 'ShadowRoot | null' is not assignable to type 'WritableDraft<ShadowRoot> | null'.
                            Type 'ShadowRoot' is not assignable to type 'WritableDraft<ShadowRoot>'.
                              Types of property 'childNodes' are incompatible.
                                Type 'NodeListOf<ChildNode>' is not assignable to type 'WritableDraft<NodeListOf<ChildNode>>'.
                                  'number' index signatures are incompatible.
                                    Type 'ChildNode' is not assignable to type 'WritableDraft<ChildNode>'.
                                      Types of property 'parentElement' are incompatible.
                                        Type 'HTMLElement | null' is not assignable to type 'WritableDraft<HTMLElement> | null'.
                                          Type 'HTMLElement' is not assignable to type 'WritableDraft<HTMLElement>'.
                                            Types of property 'assignedSlot' are incompatible.
                                              Type 'HTMLSlotElement | null' is not assignable to type 'WritableDraft<HTMLSlotElement> | null'.
                                                Type 'HTMLSlotElement' is not assignable to type 'WritableDraft<HTMLSlotElement>'.
                                                  The types of 'style.parentRule' are incompatible between these types.
                                                    Type 'CSSRule | null' is not assignable to type 'WritableDraft<CSSRule> | null'.
                                                      Type 'CSSRule' is not assignable to type 'WritableDraft<CSSRule>'.
                                                        Types of property 'parentStyleSheet' are incompatible.
                                                          Type 'CSSStyleSheet | null' is not assignable to type 'WritableDraft<CSSStyleSheet> | null'.
                                                            Type 'CSSStyleSheet' is not assignable to type 'WritableDraft<CSSStyleSheet>'.
                                                              Types of property 'ownerNode' are incompatible.
                                                                Type 'Element | ProcessingInstruction | null' is not assignable to type 'WritableDraft<Element> | WritableDraft<ProcessingInstruction> | null'.
                                                                  Type 'Element' is not assignable to type 'WritableDraft<Element> | WritableDraft<ProcessingInstruction> | null'.
    48 |             setCache((d) => {
    49 |               if (img) {
  > 50 |                 d.image[imageSrc] = img;
       |                 ^^^^^^^^^^^^^^^^^
    51 |               }
    52 |             });
    53 |           }


直觉上,我理解错误的发生是因为并不是Elements的所有属性都可以以useImmer期望的方式修改。所以我的问题是,如何防止这个错误,或者,如何“告诉”useImmer,我不打算编辑图像,只是得到/设置它们?

vuktfyat

vuktfyat1#

从Cast实用程序文档中,我们可以使用castDraft
将任何不可变类型转换为其可变对应类型。这只是一个演员表,实际上并没有做任何事情。

import { castDraft } from 'immer';
import React, { useEffect } from 'react';
import { Updater, useImmer } from 'use-immer';

type Cache = {
    image: Record<string, HTMLImageElement>;
};

const initialCache = {
    image: {},
};

function Child(props: { cache: Cache; setCache: Updater<Cache> }) {
    useEffect(() => {
        (async () => {
            const imageKey = 'forDemonstrationPurposes';
            const maybeImg = props.cache.image[imageKey];
            let img = maybeImg;
            if (!img) {
                img = new Image();
                img.src = 'Some base64 string';
                props.setCache((d) => {
                    d.image[imageKey] = castDraft(img);
                });
            }
        })();
    }, []);

    return null;
}

function Component() {
    const [cache, setCache] = useImmer(initialCache);
    return (
        <Child
            cache={cache}
            setCache={setCache}
        />
    );
}

字符串
软件包版本:

"immer": "^10.0.2",
"use-immer": "^0.9.0"

相关问题