首页 > 解决方案 > 即使参数的类型正确,Typescript 编译错误

问题描述

打字稿抛出这个编译错误:

Argument of type '(state: string, action: Action<string>) => string' is not assignable to parameter of type 'Reducer<string, Action<string>>'.
  Types of parameters 'state' and 'state' are incompatible.
    Type 'string | undefined' is not assignable to type 'string'.
      Type 'undefined' is not assignable to type 'string'.  TS2345

我的功能如下所示:

function todos(state: string, action: Action<string>)

我无法理解的是,首先,state参数不可为空,但编译器却说它可以为空。其次,错误消息自相矛盾,在第一行中说函数的类型是(state: string, action: Action<string>) => string(这是正确的),而第三行说第一个参数是string | undefined

我刚刚开始学习 typescript 和 react-redux,所以我真的很困惑。

编辑:

此外,我尝试调用作为第一个参数传递的函数,undefined但编译器抱怨它不像预期的那样可以为空,但后来又抱怨它可以为空!

编辑 2

我忘了说我正在使用该函数从 reduxtodos调用函数,如下所示:createStorecreateStore(todos)

完整的代码是这样的:

import React from 'react';
import ReactDOM from 'react-dom';
import './styles/index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {Action, createStore} from 'redux'
import {Provider} from "react-redux";

function todos(state: string, action: Action<string>) {
    return state
}

let store = createStore(todos); // PROBLEM HERE
let app = (
    <Provider store={store}>
        <App/>
    </Provider>
)

ReactDOM.render(app, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers:
serviceWorker.unregister();

另外,我知道combineReducers通常使用它并且不state应该是 a string,但我纯粹出于好奇(作为打字稿的初学者)问这个问题,因为我知道有明显的解决方法。

我也尝试使用string[]作为状态的类型,但抛出了相同的错误,除了它是string[] | undefined在这个时候。

编辑 3:

我意识到如果我为状态添加一个默认值,例如function todos(state: string = "", action: Action),错误就会消失。但这是为什么呢?鉴于 state 已经是必需的、不可为空的参数,这不是多余的吗?在 Swift 和 Kotlin 中,只有当您使用 nil 状态参数调用函数时才会抛出错误todos,但您不需要在参数的定义中提供默认值。那么为什么打字稿会出现这种情况呢?这是设计使然吗?

标签: reactjstypescriptreduxreact-redux

解决方案


回答编辑 3 中提到的确切问题,使函数参数成为默认值(正如您通过为 指定默认值所做的那样state)将此类参数的类型更改为string | undefined(在您的情况下)。这也相当于参数后的问号。所以下面三个函数的调用签名是一样的

function todos(state: string | undefined, action: Action<string>)
function todos(state?: string, action: Action<string>)  // This example is not completly correct as you should make action optional too, by addint ? to it name
function todos(state: string = "", action: Action<string>)

我从 Typescript 文档中推荐这一章。

本主题开头的错误指出,Type 'string | undefined' is not assignable to type 'string'.因此添加默认值使其成为满足编译器state的类型。string | undefined


推荐阅读