reactjstypescript

How to get an element's dom nodeName from a keyDown event


I have a function for a keyDown event:

<Table.Row
    key={item.id + "-" + index}
    className="align-top"
    onKeyDown={actionOnEnter(() => {
        saveRow(index);
    })}
>

I can see in console that event.target property has a nodeName property. I would like to check in the event function the value of the nodeName property.

export const actionOnEnter = (fn: () => void) => (e: React.KeyboardEvent) => {
    console.log(e.target.nodeName);
    if (e.key === "Enter") {
        e.preventDefault();
        fn();
    }
};

But, I get typescript error if I try to get a value of nodeName property:

TS2339: Property  nodeName  does not exist on type  EventTarget

Which property and type should I use to get a node element which triggered the event?


Solution

  • In the context of a React.KeyboardEvent<Element>, the target property is typed as an EventTarget. However, EventTarget does not have a nodeName property; this property is specific to Node.

    The EventTarget interface in React only includes methods for adding, removing, or dispatching events.

    If we know that the event is attached to an element, we can cast the target property to a Node. Alternatively, we can cast it as an Element or HTMLElement, depending on the desired specificity.

    export const actionOnEnter = (fn: () => void) => (e: React.KeyboardEvent) => {
      const el = e.target as Node;
    
      console.log(el.nodeName); // Property is now available
      
      if (e.key === "Enter") {
          e.preventDefault();
          fn();
      }
    };
    

    For safer type checking, we can use a guard clause to ensure the target is an instance of Node before accessing nodeName:

    export const actionOnEnter = (fn: () => void) => (e: React.KeyboardEvent) => {
      if (e.target instanceof Node) {
        console.log(e.target.nodeName); // The `target` is inferred as a `Node`
      }
    
      if (e.key === "Enter") {
          e.preventDefault();
          fn();
      }
    };
    

    The guard clause narrows the type of target within the if block, allowing it to be treated as a Node. This ensures type safety and eliminates the need for temporary variables or unsafe casting in that scope.