#Argument of type 'N[NKey]' is not assignable to parameter of type 'N[]'.

3 messages · Page 1 of 1 (latest)

vivid moss
#

import { View } from "react-native";
import React, {FC, PropsWithChildren, Dispatch, SetStateAction, useState } from "react";

// import { FCC } from "app/types/IReact"; // FCC = Functional Component with children prop
type FCC<P = {}> = FC<PropsWithChildren<P>>;


type WithId<T> = T & { $id: string };

type NodeWithNodesProp<
    NKey extends string,
    LKey extends string,
    N extends WithId<NodeWithNodesAndLeafsProp<NKey, LKey, N, L>>,
    L extends WithId<{}>,
> = {
    [Nkey in NKey]: WithId<NodeWithNodesAndLeafsProp<NKey, LKey, N, L>>[];
};

type NodeWithLeafsProp<LKey extends string> = {
    [Lkey in LKey]: WithId<{}>[];
};

type NodeWithNodesAndLeafsProp<
    NKey extends string,
    LKey extends string,
    N extends WithId<NodeWithNodesAndLeafsProp<NKey, LKey, N, L>>,
    L extends WithId<{}>,
> = WithId<NodeWithNodesProp<NKey, LKey, N, L> & NodeWithLeafsProp<LKey>>;

interface ITreeView<
    NKey extends string,
    LKey extends string,
    N extends WithId<NodeWithNodesAndLeafsProp<NKey, LKey, N, L>>,
    L extends WithId<{}>,
> {
    treeData: {
        nodes: N[];
        rootLeafs: L[];
    };
    isCollapsed: boolean;
    nodeArrKey: NKey;
    leafArrKey: LKey;
    renderNode: (
        node: N,
        setCollapse: Dispatch<SetStateAction<boolean>>,
    ) => JSX.Element;
    renderLeaf: (node: L) => JSX.Element;
}
#
export const TreeView = <
    NKey extends string,
    LKey extends string,
    N extends WithId<NodeWithNodesAndLeafsProp<NKey, LKey, N, L>>,
    L extends WithId<{}>,
>(
    props: ITreeView<NKey, LKey, N, L>,
) => {
    const { treeData, nodeArrKey, leafArrKey, renderNode, renderLeaf } = props;
    const _renderNodes = (nodesArr: (typeof treeData)["nodes"]) => {
        return nodesArr.map(node => {
            const nodeObj = node[nodeArrKey];
            const childNodes = nodeObj && _renderNodes(nodeObj); // here's the TS Error

            const leafObj = node[leafArrKey];
            const childLeafs = leafObj && _renderLeaf(leafObj);
            return (
                <TreeWrapper
                    isCollapsed={props.isCollapsed}
                    key={node.$id}
                    node={setCollapse => renderNode && renderNode(node, setCollapse)}
                    childNodes={childNodes}
                    childLeafs={childLeafs}
                />
            );
        });
    };
    const _renderLeaf = (leaf: (typeof treeData)["rootLeafs"]) => {
        return leaf.map(node => {
            return (
                <React.Fragment key={node.$id}>
                    {renderLeaf && renderLeaf(node)}
                </React.Fragment>
            );
        });
    };
    return (
        <View>
            {_renderNodes(treeData["nodes"])}
            {_renderLeaf(treeData["rootLeafs"])}
        </View>
    );
};
#

.

EXTRAS


interface ITreeWrapper {
    isCollapsed: boolean;
    node: (setCollapse: Dispatch<SetStateAction<boolean>>) => JSX.Element;
    childNodes: JSX.Element[];
    childLeafs: JSX.Element[];
}
const TreeWrapper: FCC<ITreeWrapper> = props => {
    const { node, childNodes, childLeafs, isCollapsed } = props;
    const [wrapperMinHt, setWrapperMinHt] = useState(0);
    const [collapse, setCollapse] = useState(isCollapsed);
    const allowCollapse = collapse && !!wrapperMinHt;
    const wrapperHt = allowCollapse ? wrapperMinHt : "auto";
    // TODO: animate height change
    return (
        <View style={{ height: wrapperHt, overflow: "hidden" }}>
            <View onLayout={e => setWrapperMinHt(e.nativeEvent.layout.height)}>
                {node(setCollapse)}
            </View>
            {childNodes}
            {childLeafs}
        </View>
    );
};

/////////////////////////////////// Usage of the TreeView component//////////////////////////

type IBookmark = {
    $id: string;
    // ..... others
}
type IFolder = {
    $id: string;
    folders: IFolder[];
    bookmarks: IBookmark[];
    /// ..... others
}
export function TreePanel() {
    
    return (
        <TreeView
            treeData={{
                nodes: [] as IFolder[],
                rootLeafs: [] as IBookmark[],
            }}
            isCollapsed
            nodeArrKey="folders"
            leafArrKey="bookmarks"
            renderNode={(node, setCollapse) => (<React.Fragment></React.Fragment>)}
            renderLeaf={node => <React.Fragment></React.Fragment>}
        />
    );
}