首页 > 解决方案 > 如何修复错误“元素隐式具有‘任何’类型,因为类型的表达式

问题描述

我是 TypeScript 的初学者。

我曾经ts migrate在我的 react 应用程序中用 TypeScript 替换 JavaScript,但出现以下错误。

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{}'. TS7053

导致错误的文件如下。

import React, { useState, useEffect, useCallback} from 'react';
import './assets/styles/style.css';
import {AnswersList, Chats} from './components/index';
import FormDialog from './components/Forms/FormDialog';
import {db} from './firebase/index';

const App = () => {
  const [answers, setAnswers] = useState([]);
  const [chats, setChats] = useState([]);
  const [currentId, setCurrentId] = useState("init");
  const [dataset, setDataset] = useState({});
  const [open, setOpen] = useState(false);

  const displayNextQuestion = (nextQuestionId: any, nextDataset: any) => {
    addChats({
      text: nextDataset.question,
      type: 'question'
    })

      setAnswers(nextDataset.answers)
      setCurrentId(nextQuestionId)
  }

  const selectAnswer = (selectedAnswer: any, nextQuestionId: any) => {
    switch(true) {
      case (nextQuestionId === 'contact'):
          handleClickOpen()
          break;
      
      case (/^https:*/.test(nextQuestionId)):
          const a = document.createElement('a');
          a.href = nextQuestionId;
          a.target = '_blank';
          a.click();
          break;

      default:
          addChats({
              text: selectedAnswer,
              type: 'answer'
          })
        setTimeout(() => displayNextQuestion(nextQuestionId, dataset[nextQuestionId]), 500) //Here's where the error occurs
        break;
    }
  }

  const addChats = (chat: any) => {
    setChats(prevChats => {
      return [...prevChats, chat]
    })
  }

  const handleClickOpen = () => {
    setOpen(true)
  };

  const handleClose = useCallback(() => {
      setOpen(false)
  }, [setOpen]);


  useEffect(() => { 
    (async() => {
      const initDataset = {};

      await db.collection('questions').get().then(snapshots => {
        snapshots.forEach(doc => {
          const id = doc.id
          const data = doc.data()
          initDataset[id] = data
        })
      })

      setDataset(initDataset)
      displayNextQuestion(currentId, initDataset[currentId])
    })()
  }, [])

  useEffect(() => {
      const scrollArea = document.getElementById('scroll-area')
      if (scrollArea) {
        scrollArea.scrollTop = scrollArea.scrollHeight
      } 
  })
  
  return(
    <section className="c-section"> 
      <div className="c-box">
        <Chats chats={chats} />
        <AnswersList answers={answers} select={selectAnswer} />
        <FormDialog open={open} handleClose={handleClose} />
      </div>
    </section>
  );
}

export default App;

首先,我定义了displayNextQuestion使用接口的类型如下,但是错误没有解决,我们又得到了一个错误。

  interface StringKeyObject {
    [key: string]: any;
  }  

  const displayNextQuestion: StringKeyObject = (nextQuestionId: any, nextDataset: any) => {
    addChats({
      text: nextDataset.question,
      type: 'question'
    })

      setAnswers(nextDataset.answers)
      setCurrentId(nextQuestionId)
  }

This expression is not callable. Type 'StringKeyObject' has no call signatures. TS2349

接下来,displayNextQuestion' 的参数nextQuestionId是任何类型的,所以我将它设置为字符串,但错误没有改变。

我做了很多研究,不知道如何解决这个错误,所以我问。

标签: javascriptreactjstypescript

解决方案


当你说:

const displayNextQuestion: StringKeyObject = (...)

这意味着显然不是displayNextQuestion类型。StringKeyObject这是一个功能。您也没有从此函数返回任何内容,因此返回类型也是void如此。

现在让我们看看参数。nextQuestionId必须是 astring因为你使用setCurrentId(nextQuestionId)它的默认状态是init.

nextDataset应该是一个具有一系列答案的对象,例如:

{ 
  answers: [...],
  ...
}

将它们放在一起应该可以:

const displayNextQuestion = (nextQuestionId: string, nextDataset: { answers: Array<Answer> } ) => {
  addChats({
   text: nextDataset.question,
   type: 'question'
  })

  setAnswers(nextDataset.answers)
  setCurrentId(nextQuestionId)
}

我建议您为数据集定义一个接口以及answer

interface Answer {
  // ...whatever that answer has
}

interface Dataset {
  answers: Array<Answer>;
  // ...other things that Dataset has
}

并明确设置类型useState

interface Question {}

interface Chat {}

interface Answer { }

interface Dataset {
  answers: Array<Answer>;
  question: any;
  [k: string]: Question; 
  // ^ This signifies that Dataset can have any key as long as it's string 
  // and its value is of type Question (best I could guess based on the 
  // usage at "dataset[nextQuestionId])"
}

const App = () => {
  const [answers, setAnswers] = useState<Array<Answer>>([]);
  const [chats, setChats] = useState<Array<Chat>>([]);
  const [currentId, setCurrentId] = useState("init");
  const [dataset, setDataset] = useState<Dataset>({ answers: [], question: null });
  const [open, setOpen] = useState(false);
  // ...

推荐阅读