NK-dev
@NK-dev (N K)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

TypeScriptのエラーIntrinsicAttributesの解決法の模索

解決したいこと

atomから参照してきた状態変数をmap関数で展開して展開したものを子コンポーネントにpropsで受け渡す時にコンポーネントにエラーが出てしまっているので助言を頂きたいです(下記に記載しているTodoList.tsx中に発生)。

発生している問題・エラー

TodoList.tsx
 '{ key: number; todo: DATA; }' を型 'IntrinsicAttributes & DATA' に割り当てることはできません
  プロパティ 'todo' は型 'IntrinsicAttributes & DATA' に存在しません

該当するソースコード

TodoList.tsx
import React from 'react';
import { useRecoilValue } from 'recoil';
import { todoListState } from '../State/atom';
import { DATA } from '../types/DataType';
import TodoItem from './TodoItem';
import TodoItemCreator from './TodoItemCreator';
import TodoListStatus from './TodoListStatus';

const TodoList: React.FC<DATA> = () => {
  const todoList = useRecoilValue(todoListState);

  return (
    <div>
      <h1>初めてのRecoil</h1>
      <TodoListStatus />
      <TodoItemCreator />
      {todoList.map((todo) => (
//※ここのtodo={todo}の左辺のtodoで上記エラーが吐かれています
        <TodoItem key={todo.id} todo={todo} />
      ))}
    </div>
  );
};

export default TodoList;
TodoItem.tsx
import React from 'react';
import { useRecoilState } from 'recoil';
import { todoListState } from '../State/atom';
import { DATA } from '../types/DataType';

const TodoItem: React.FC<DATA> = (todo) => {
  const [todoList, setTodoList] = useRecoilState(todoListState);

  const deleteItem = (id: number) => {
    const newTodos = todoList.filter((todo) => todo.id !== id);
    setTodoList(newTodos);
  };

  const toggleCompletion = (id: number, isComlete: boolean) => {
    const toggleChecked = todoList.map((todo) => {
      if (todo.id === id) {
        todo.isComplete = !isComlete;
      }
      return todo;
    });
    setTodoList(toggleChecked);
  };

  return (
    <div>
      <div key={todo.id}>
        <button onClick={() => toggleCompletion(todo.id, todo.isComplete)}>
          {todo.isComplete ? '完了' : '未完了'}
        </button>
        {todo.title}
        <span className='deletefunc' onClick={() => deleteItem(todo.id)}>
          削除
        </span>
      </div>
    </div>
  );
};

export default TodoItem;
atom.ts
import { atom } from 'recoil';
import { DATA } from '../types/DataType';

export const todoListState = atom<Array<DATA>>({
  key: 'todoListState',
  default: [
    {
      id: 0,
      title: '送信設定',
      isComplete: false,
    },
  ],
});
selector.ts
import { selector } from 'recoil';
import { todoListState } from './atom';

export const todoListStatusState = selector<number>({
  key: 'todoListStatusState',
  get: ({ get }) => {
    const todoList = get(todoListState);
    const totalNum = todoList.length;
    return totalNum;
  },
});
DataType.ts
export type DATA = {
  id: number;
  title: string;
  isComplete: boolean;
};

自分で試したこと

・「intrinsicattributes' に割り当てることはできません。」と検索したところ,childrenの型を定義してあげる必要があると書いてあったのですが、違いました。

・子コンポーネントに型指定をしてあげて受け取りをすることはできました。

TodoItem.tsx
const TodoItem: React.FC<DATA> = (todo) => {

実行環境

package.json
  "@types/jest": "^27.5.2",
    "@types/node": "^16.11.68",
    "@types/react": "^18.0.21",
    "@types/react-dom": "^18.0.6",
    "@types/styled-components": "^5.1.26",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "recoil": "^0.7.6",
    "typescript": "^4.8.4",
    "web-vitals": "^2.1.4"
1

2Answer

Propsの中身は{}の中身に渡されます.
todoごとPropsで渡すのであれば,受け側は次のように型定義する必要があります.

type ItemProps = {
  todo: DATA
}

const TodoItem: React.FC<ItemProps> = ({todo}) => {
ちなみに

よほどのことがない限り@types/reactFCは使う必要はありません.

const TodoItem = ({todo}:ItemProps) => {

それとPropsを受け取らないコンポーネントに不要な型定義するのはやめましょう.

-const TodoList: React.FC<DATA> = () => {
+const TodoList = () => {
2Like

Comments

  1. @NK-dev

    Questioner

    お忙しい中ご返信ありがとうございます。
    新しくpropsように型定義する必要があるんですね。propsの受け取る予定のないものに型定義しなしのはご指摘ありがとうございます!
    TodoItem: React.FC<ItemProps> = ({todo})だと無事にエラー解決しました。
    ItemPropsの箇所をそのままDATAで型定義すると({todo})のpropsがエラーになってしまします。このようにDATA型からtemPropsに新しく型を定義するのはどのような違いがあって行うのでしょうか。

ItemPropsの箇所をそのままDATAで型定義すると({todo})のpropsがエラーになってしまします。このようにDATA型からtemPropsに新しく型を定義するのはどのような違いがあって行うのでしょうか。

まず,

<TodoItem todo={todo} />

は以下のシンタックスシュガーです.

React.createElement(TodoItem, {todo:todo}, null)

属性のように書いた部分が1個のobject(これがpropsです)に格納されるのがお分かりいただけるかと思います.propsへの型定義はこのobjectに対する定義となります.

DATA型は{ id: number; title: string; isComplete: boolean; }ですが,上から分かるようにtodo={todo}と渡した場合はprops{todo:DATA}となり合致しません.
それゆえpropsに対する型定義は{todo:DATA}とします.

1Like

Comments

  1. @NK-dev

    Questioner

    お忙しい中ご回答ありがとうございます!
    丁寧に説明ありがとうございます。理解できました。これからもコードを書いて理解に努めたいと思います。ありがとうございました!

Your answer might help someone💌