dai_designing
@dai_designing (Daisuke Mori)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

[React] JavescriptからTypescriptにしたい

解決したいこと

ReactのJavescriptでうまくいったデータをそのまま、
typescriptに持ってきたらエラーとなります。
解決方法を教えて下さい。

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

Failed to compile.

/Users/daisukemoriair/Desktop/react-animation/src/components/Api.tsx
TypeScript error in /Users/daisukemoriair/Desktop/react-animation/src/components/Api.tsx(27,28):
Property 'id' does not exist on type 'never'.  TS2339

    25 |       <main>
    26 |         {articles.map((item) => (
  > 27 |             <div key={item.id}>
       |                            ^
    28 |                 <p className="title">
    29 |                   {item.title}
    30 |                 </p>

該当するソースコード

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const Api: React.FC = () => {
  const URL = 'http://api.moemoe.tokyo/anime/v1/master/2020/4';

  const [articles, setArticles] = useState([]);
  console.log(articles);

  useEffect(() => {
      fetchArticles();
  }, []);

  const fetchArticles = async () => {
      try {
        const res = await axios.get(URL);
        setArticles(res.data);
      } catch (error) {
        console.error(error);
      }
  }

  return (
    <div className="top">
      <main>
        {articles.map((item) => (
            <div key={item.id}>
                <p className="title">
                  {item.title}
                </p>
                <a
                  href={item.public_url}
                  rel="noopener noreferrer"
                  target="_blank">Page</a>
                <a
                  href={`https://twitter.com/${item.twitter_account}`}
                  rel="noopener noreferrer"
                  target="_blank">Twitter</a>
            </div>
        ))}
      </main>
    </div>
  );
}

export default Api;

自分で試したこと

関数のところに: React.FCを付加

0

2Answer

@types/react で定義されている useState の型は

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];

となっているので、 useState([]) の戻り値は [[], Dispatch<SetStateAction<[]>>] になります。
[] は空の tuple ですから、 [][number] の型は never となり、 [].map((v) => {}) とすると v の型も never になります。
色々やり方はありますがとりあえずエラーを解消するなら、

interface Article {
  id: string,
  /* ... */
}

const [articles, setArticles] = useState<Article[]>([]);

などと型を明示すれば良いでしょう

3Like

どうやって変換しましたか?
Javescript には詳しくないのですが、Javascript ではうまく行きました。

  • src/Api.js

に例文のソースをコピペして、以下のように実行すると変換できました。

npm install js-to-ts-converter
npx js-to-ts-converter src/
npxのコマンド結果
info:   Processing directory: '/home/user1/Documents/typescript/src' 
info:   Processing the following source files: 
info:     /home/user1/Documents/typescript/src/Api.js 
info:    
Converting source files... This may take anywhere from a few minutes to  
tens of minutes or longer depending on how many files are being  
converted. 
 
info:   Adding property declarations to JS Classes... 
verbose:        Parsing JS classes in the codebase... 
info:   Renaming .js files to .ts 
info:   Making parameters optional for calls that supply fewer args than function parameters... 
verbose:        Beginning routine to mark function parameters as optional when calls exist that supply fewer args than parameters... 
verbose:        Parsing function/method/constructor calls from codebase. 
verbose:        Finding all calls to class constructors... 
verbose:          Processing classes in source file: /home/user1/Documents/typescript/src/Api.tsx 
verbose:        Finding all calls to functions/methods... 
verbose:          Processing functions/methods in source file: /home/user1/Documents/typescript/src/Api.tsx 
verbose:        Marking parameters as optional 
info:   Outputting .ts files: 
info:     /home/user1/Documents/typescript/src/Api.tsx 

結果は以下となりました。


Api.tsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';

const Api: React.FC = () => {
  const URL = 'http://api.moemoe.tokyo/anime/v1/master/2020/4';

  const [articles, setArticles] = useState([]);
  console.log(articles);

  useEffect(() => {
      fetchArticles();
  }, []);

  const fetchArticles = async () => {
      try {
        const res = await axios.get(URL);
        setArticles(res.data);
      } catch (error) {
        console.error(error);
      }
  }

  return (
    <div className="top">
      <main>
        {articles.map((item) => (
            <div key={item.id}>
                <p className="title">
                  {item.title}
                </p>
                <a
                  href={item.public_url}
                  rel="noopener noreferrer"
                  target="_blank">Page</a>
                <a
                  href={`https://twitter.com/${item.twitter_account}`}
                  rel="noopener noreferrer"
                  target="_blank">Twitter</a>
            </div>
        ))}
      </main>
    </div>
  );
}

export default Api;
1Like

Comments

  1. @dai_designing

    Questioner

    もともとjsで書いてるReactも
    このコマンドでtsに変更できるんですか?
    問題なく変更ってできるのでしょうか?
    どこかで動かなくなるっていうリスクはございませんか?

Your answer might help someone💌