You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Next.js+TypeScript待办列表接口赋值TypeScript报错求助

待办列表应用TypeScript类型错误问题

我是React+Next.js+TypeScript新手,正在开发一个待办列表应用,定义了如下接口和状态:

interface listData {
  text: string,
  isDone: boolean,
  viewMode?: { display: '' },
  editMode?: { display: 'none' },
}

const [list, setList] = useState<listData[]>([]);

const addList = (item: any) => {
  if (item !== "") {
    const newList = [...list, { text: item, isDone: false, viewMode: { display: '' }, editMode: { display: 'none' } }];
    localStorage.setItem('listData', JSON.stringify([...list, { text: item, isDone: false, viewMode: { display: '' }, editMode: { display: 'none' } }]));
    setList(newList);
  };
}

调用setList(newList)时触发TypeScript类型错误,报错信息如下:

Argument of type '(listData | { text: string; isDone: boolean; viewMode: { display: string; }; editMode: { display: string; }; })[]' is not assignable to parameter of type 'SetStateAction<listData[]>'.
  Type '(listData | { text: string; isDone: boolean; viewMode: { display: string; }; editMode: { display: string; }; })[]' is not assignable to type 'listData[]'.
    Type 'listData | { text: string; isDone: boolean; viewMode: { display: string; }; editMode: { display: string; }; }' is not assignable to type 'listData'.
      Type '{ text: string; isDone: boolean; viewMode: { display: string; }; editMode: { display: string; }; }' is not assignable to type 'listData'.
        The types of 'viewMode.display' are incompatible between these types.
          Type 'string' is not assignable to type '""'.ts(2345)

viewMode和editMode用于控制DOM元素的CSS display属性,点击编辑按钮时会切换两者的display值。组件渲染相关代码:

return (
  <>
    <div className={styles.bodyOuterDiv} >
      ...
        <ul >
          {list.map((item, index) => {
            return (
              <li key={index} className={styles.todoListOuterLi} >
                <div className={item.isDone ? styles.todoListItemsWithIsDone : styles.todoListItems} style={item.viewMode}>
                        {item.text}
                </div>
                <textarea className={styles.todoListTextArea} value={item.text} onChange={(e) => { setItem(e.target.value) }} style={item.editMode} />
                      ...
               </li>
             );
          })}
        </ul>
       ...
     </div>
  </>
);

问题原因与解决方法

问题根源

listData接口中,viewMode.display被定义为空字符串字面量类型(''),editMode.display被定义为**'none'字面量类型**。但在addList创建新项时,TypeScript会自动把{ display: '' }里的''推断为更宽泛的string类型,这就和接口里的字面量类型不匹配,从而触发类型错误。

另外,后续你需要切换display的值(比如把viewMode的display改成'none',editMode改成''),如果接口固定为单一字面量类型,切换操作也会触发新的类型错误。

解决方案

修正listData接口,将display的类型改为允许的CSS display值联合类型:

// 定义你需要用到的display值集合
type DisplayValue = '' | 'none';

interface listData {
  text: string,
  isDone: boolean,
  viewMode?: { display: DisplayValue },
  editMode?: { display: DisplayValue },
}

修改后:

  1. 新创建项中的display: ''和display: 'none'会被正确识别为DisplayValue类型,与接口匹配,不再报错。
  2. 后续切换display值时,只要值在DisplayValue范围内,TypeScript就不会拦截操作。

额外优化

  • 将addList的参数类型从any改为string,符合TypeScript类型安全要求:
    const addList = (item: string) => {
      // 原有逻辑
    }
    
  • 抽离新项创建逻辑,避免重复代码:
    const createNewTodoItem = (text: string): listData => {
      return {
        text,
        isDone: false,
        viewMode: { display: '' },
        editMode: { display: 'none' }
      };
    }
    
    const addList = (item: string) => {
      if (item.trim() !== "") { // 过滤空白字符
        const newItem = createNewTodoItem(item);
        const newList = [...list, newItem];
        localStorage.setItem('listData', JSON.stringify(newList));
        setList(newList);
      };
    }
    

内容的提问来源于stack exchange,提问作者Austin7L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 20:57:19