【问题标题】:What is "not assignable to parameter of type never" error in TypeScript?什么是 TypeScript 中的“不能分配给永不类型的参数”错误?
【发布时间】:2022-06-19 06:33:31
【问题描述】:

代码是:

const foo = (foo: string) => {
  const result = []
  result.push(foo)
}

我收到以下 TS 错误:

[ts] \'string\' 类型的参数不能分配给 \'never\' 类型的参数。

我究竟做错了什么?这是一个错误吗?

  • const result: [] = [] => const result: string[],不是只是[],但是string[],如果你不知道数组里面的类型,你总是可以回退到any[]

标签: typescript


【解决方案1】:

您所要做的就是将您的result 定义为一个字符串数组,如下所示:

const result : string[] = [];

不定义数组类型,默认为never。因此,当您尝试向其添加字符串时,它是类型不匹配的,因此它抛出了您看到的错误。

【讨论】:

  • 这对我来说似乎很奇怪,为什么默认为 never[] ?除了“一个永远为空的数组”之外,还有其他用途吗?
  • 我完全同意,因为老实说,我想不出一个nevers 数组会有用的用例。但是在调查它时,我遇到了这个answer,它有很好的信息。
  • 默认类型不应该是“任何”吗?当您声明一个变量 (let x;) 时,默认情况下它的类型为 any。不是never
  • @VincentBuscarello 我猜,这种默认值的主要目的是让一个总是向他们的数组添加类型;但错误消息绝对没有帮助。
  • 我总是想知道这些更改在源代码中发生的位置以便更好地理解,所以对于那些好奇的人来说,请参阅:github.com/Microsoft/TypeScript/issues/9976github.com/microsoft/TypeScript/pull/8944
【解决方案2】:

另一种方法是:

const result: any[] = [];

【讨论】:

  • 实际上使用 any 并不是一个好的选择,因为它基本上会关闭所有 TypeScript 功能。这是一种解决方法,可能会导致各种错误。
  • 是的。但有时其他任何东西都不起作用,尤其是当您使用第三方库时..
  • const result: any[] = [] 不会更准确吗?它是任何非数组,并且数组被视为任何
  • @g00dnatur3 是对的。如果您必须使用 any,那么至少指定它是任何类型的项目的数组。
【解决方案3】:

由于遗留原因,这似乎是打字稿中的一些奇怪行为。如果你有代码:

const result = []

通常它会被视为你写的:

const result:any[] = []

但是,如果您同时拥有noImplicitAny FALSE,strictNullChecks TRUE 在您的 tsconfig 中,它被视为:

const result:never[] = []

这种行为违背了所有逻辑,恕我直言。打开空检查会更改数组的条目类型??然后开启noImplicitAny居然恢复了any的使用,没有任何警告??

当您真正拥有any 的数组时,您不需要使用额外的代码来指示它。

【讨论】:

  • 诚然,这绝对是不直观的,一个称为“无隐含任何”的参数应该暗示任何时候某事都会被假定为任何 - 它不是。此外,隐含的“从不”似乎很愚蠢,为什么不简单地声明一个错误:数组没有声明其类型。恕我直言,这应该完全取决于 noImplicitAny,而不是组合。
  • 我认为为大型回购做出贡献的人有时会过度设计它。至少我们知道应该设置哪些标志以使其直观。至于我,我将两个标志都设置为 true 并且感觉很好。
【解决方案4】:

我在 ReactJS 函数组件中遇到了同样的错误,使用 ReactJS useState 钩子。

解决方案是在初始化时使用尖括号声明 useState 的类型:

// Example: type of useState is an array of string
const [items , setItems] = useState<string[]>([]); 

【讨论】:

    【解决方案5】:

    我在使用 ReactJs Hook 时在ReactJS statless 函数中遇到了同样的错误 useState。 我想设置对象数组的状态,所以如果我使用以下方式

    const [items , setItems] = useState([]);
    

    并像这样更新状态:

     const item = { id : new Date().getTime() , text : 'New Text' };
     setItems([ item , ...items ]);
    

    我收到错误:

    '{ id: number; 类型的参数文本:任何 }' 都不能分配给“从不”类型的参数

    但如果这样做,

    const [items , setItems] = useState([{}]);
    

    错误消失了,但有一个项目0 索引没有任何数据(不想要那个)。

    所以我找到的解决方案是:

    const [items , setItems] = useState([] as any);
    

    【讨论】:

    • 实际上,我认为您的解决方案的更好版本是 const [items , setItems] = useState([] as string[]);
    【解决方案6】:

    我找到的解决方案是

    const [files, setFiles] = useState([] as any);
    

    【讨论】:

    • 使用as any 会阻碍静态类型系统。如果您知道数组中将包含哪些类型,最好明确表示:const myArray: string[] = []; const [files, setFiles] = useState(myArray);。注意在useState 的情况下,你可以传入一个泛型,而不是:const [files, setFiles] = useState&lt;string[]&gt;([]);
    • 这是一个不好的做法。通过使用as any,您只是在说“不,我不想使用打字稿”。另一方面,宁亚的回答已经足够好了。更好的方法应该是接口,但我也是打字稿的新手,所以我不确定如何接口这个。
    • 我不敢相信这个答案有这么多赞成,这基本上是在沉默打字稿,完全违背了它的目的。
    • @jmealy 你的回答对我有用,应该是解决这个问题的方法。按照你的例子,我在我的组件外部声明了一个constconst initialEmailsState: string[] = [];,并在组件内部使用它,useStateconst [emails, setEmails] = useState(initialEmailsState);,现在我可以毫无问题地设置emailssetEmails([...emails, createOption(inputValue)]);
    • 不要这样做。请使用泛型进行元素类型。
    【解决方案7】:

    假设您的 linter 可以使用“任何”类型:

    如果您不知道将填充数组的值的类型,您可以这样做并结果将推断类型。

    const result: any[] = []
    

    2022 年 4 月 26 日:回到这一点,我认为您可能一直在寻找的解决方案可能是这样的:

    const foo = (foo: string) => {
      const result: string[] = []
      result.push(foo)
    }
    

    您需要指定数组是什么结果 = []返回类型为任何[].通常你想避免任何类型,因为根据 Microsoft 的说法,它们旨在用作“逃生舱口”。

    结果是一个对象,它是一个期望类型的数组细绳值或包含字符串的内容,例如字符串 |数字.

    【讨论】:

      【解决方案8】:

      我能够通过使用 Array 关键字而不是空括号来解决这个问题:

      const enhancers: Array<any> = [];
      

      利用:

      if (typeof devToolsExtension === 'function') {
        enhancers.push(devToolsExtension())
      }
      

      【讨论】:

      • 感谢您指出。 Array 关键字是另一种好方法。如果您必须为这样的数组数组定义类型let parsed: Array&lt;[]&gt; = [];,它在语义上甚至更有用
      • @ValentineShi 你仍然可以做类似[][] 的事情。如果你想要一个数字数组之类的东西,你可以做number[][]。请注意:parsed: Array&lt;[]&gt; 这里隐含的是Array&lt;any[]&gt;
      【解决方案9】:

      错误:“any”类型的参数不能分配给“never”类型的参数。

      在 tsconfig.json -

        "noImplicitReturns": false,
      
         "strictNullChecks":false,
      

      解决方案:输入“从不”

      【讨论】:

        【解决方案10】:

        消除“strictNullChecks”:真“编译器选项”或在tsconfig.json您的 Ng 应用程序的文件。这些错误会像任何事情一样消失,您的应用程序将成功编译。

        免责声明: 这只是一种解决方法。仅当未正确处理空检查时才会出现此错误,这在任何情况下都不是完成工作的好方法。

        【讨论】:

        • 对我来说,在 tsconfig 中只是“严格”部分,当我将它设置为 false 时,你说错误消失,这是反应,而不是 angular。谢谢。
        【解决方案11】:

        错误的另一个原因。

        如果您在使用 connect()() 包装组件后导出,则道具可能会给出打字稿错误
        解决方案:我没有进行太多探索,因为我可以选择用 useSelector 钩子替换连接函数
        例如

        /* Comp.tsx */
        interface IComp {
         a: number
        }
        
        const Comp = ({a}:IComp) => <div>{a}</div>
        
        /* ** 
        
        below line is culprit, you are exporting default the return 
        value of Connect and there is no types added to that return
        value of that connect()(Comp) 
        
        ** */
        
        export default connect()(Comp)
        
        
        --
        /* App.tsx */
        const App = () => {
        /**  below line gives same error 
        [ts] Argument of type 'number' is not assignable to 
        parameter of type 'never' */
         return <Comp a={3} />
        }
        

        【讨论】:

          【解决方案12】:

          您需要在字符串数组const result: string[] = []; 中键入result

          【讨论】:

            【解决方案13】:

            定义(初始化)数组时出现错误,如下所示:

            let mainMenu: menuObjectInterface[] | [] = [];
            

            我遇到问题的代码:

            let mainMenu: menuObjectInterface[] | [] = [];
            dbresult.rows.forEach((m) => {
                if (!mainMenu.find((e) => e.menucode === m.menucode)) {
                    // Not found in mainMenu, yet
                    mainMenu.push({menucode: m.menucode, menudescription: m.menudescription})  // Here the error
                }
            })
            

            错误是:TS2322:类型“任何”不可分配给类型“从不”

            原因是该数组也使用空数组选项进行了初始化。 Typescript 看到了一个也可以为空的类型的推送。因此错误。

            将行更改为此修复了错误:

            let mainMenu: menuObjectInterface[] = [];
            

            【讨论】:

              【解决方案14】:

              你也可以添加as string[]

              const foo = (foo: string) => {
                const result = []
                (result as string[]).push(foo)
              }
              

              当它是对象的一部分时我做到了

              let complexObj = {
              arrData : [],
              anotherKey: anotherValue
              ...
              }
              (arrData as string[]).push('text')
              

              【讨论】:

                【解决方案15】:

                在最新版本的 Angular 中,您必须定义变量的类型:

                1. 如果它是一个字符串,你必须这样做:

                  公开消息:字符串 =“”;

                2. 如果是数字:

                  公共 n:数字=0;

                3. 如果是字符串表:

                  公共标签:字符串[] = [];

                4. 如果是数字表:

                  公共标签:数字[]=[];

                5. 如果是混合表:

                  公共标签:任何[] = []; .......等(对于其他类型的变量)

                6. 如果你没有定义变量的类型:默认情况下类型是 never

                  注意:在您的情况下,您必须知道表必须包含的变量类型,并选择正确的选项(如选项 3 ,4 5 )。

                【讨论】:

                  猜你喜欢
                  • 2022-01-06
                  • 2019-02-24
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多