Héctor León
Héctor León

Reputation: 2400

React Typescript - Type error between passing props to Hooks

I have created this codesandbox replicating my issue

So i created these useInput, but i got this annoying red linter errors. Its probably some basic type issue, but i can figure it out how to get rid of this issue. without any type solutions ? Thanks in advance

Error screenshot and chunk of code below, but better test in the sandbox

enter image description here

# useInput.tsx

import { useState, ChangeEvent } from "react";

export type onChangeType = (event: ChangeEvent<HTMLInputElement>) => void;
const useInput = (initialValue = "") => {
  const [value, setValue] = useState(initialValue);

  const reset = () => setValue("");

  const onChange: onChangeType = e => {
    setValue(e.target.value);
  };

  return [value, onChange, reset];
};

export default useInput;

# Input.tsx

import React, { useState, ChangeEvent } from "react";
import styled, { css } from "styled-components";

import onChangeType from "./hooks/useInput";

interface iLabelProps {
  hasContent: boolean;
}

const hasContentCSS = () => css`
  border: 5px solid royalblue;
`;

const Label = styled.label<iLabelProps>```

interface iInput {
  readonly type?: string;
  readonly name: string;
  readonly label: string;
  value?: string | number | string[] | null;
  defaultValue?: string | number | string[] | null;
  readonly onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
}

export const Input = ({
  name = "email",
  label,
  value = null,
  defaultValue = null,
  onChange = null
}: iInput) => {
  const [hasContent, setHasContent] = useState(!!defaultValue);

  const onBlur = value => {
    setHasContent(value.length > 0);
  };

  return (
    <Label hasContent={hasContent}>
      <input
        type="text"
        name={name}
        {...defaultValue && { defaultValue: defaultValue }}
        {...!defaultValue && { value: value ? value : "" }}
        {...onChange && { onChange: onChange }}
        onBlur={e => onBlur(e.target.value)}
      />
      <span>{label}</span>
    </Label>
  );
};

Upvotes: 0

Views: 839

Answers (1)

Oleksandr  Fedotov
Oleksandr Fedotov

Reputation: 384

The problem came from the incorrectly inferred type of the returned value from the useInput hook. TS think that the type is (string | onChangeType)[]. That means that string or onChangeType can be at any position in the array, while you have very fixed order.

To fix this problem you have to help it a little bit and either cast the array you return like this

return [value, onChange, reset] as [string, onChangeType, () => void];

or specify explicitly the return type of the useInput function

const useInput = (initialValue = ""): [string, onChangeType, () => void] => {...}

Upvotes: 1

Related Questions