【问题标题】:Object is of type 'unknown' typescript generics对象是“未知”类型的打字稿泛型
【发布时间】:2020-05-25 19:37:11
【问题描述】:

我有一个简单的函数,它接受一个函数作为它的参数并返回一个新函数。调用返回的函数时我得到Object is of type 'unknown'

const makeFunction = <T>(callback: (someParam: number, options: T) => any) => {

  return (options: T) => {
    const param = 4;

    return callback(param, options)  
  }  
}

上面的代码对于打字稿是可以的,但是当我调用函数时我会收到投诉

makeFunction((param, options) => {
  const a = options.optionsValue //(parameter) options: unknown,  Object is of type 'unknown'
})({optionsValue: 'some value'})

【问题讨论】:

    标签: typescript


    【解决方案1】:

    我在 try/catch 将 Typescript 升级到版本 4.4 时遇到了这个问题,并在 documentation 中找到了对此的解释。

    在简历中,他们添加了标志useUnknownInCatchVariables,如果strict,默认情况下为真。它基本上将catch 中的错误类型从any 更改为unknown,从而导致此问题。

    因此,为了升级到 4.4,您有一些选择:

    try {
        ...
    } catch(e) {
        console.log((e as Error).message)
    }
    

    或:

    try {
        ...
    } catch(e) {
        if (e instanceof Error) {
            console.log(e.message)
        }
    }
    

    或者在您的tsconfig.json 中,您可以将标志显式设置为false:

    {
        "compilerOptions": {
            "strict": true,
            "useUnknownInCatchVariables": false
        }
    }
    

    【讨论】:

      【解决方案2】:

      用以下内容更新我的tsconfig.json 对我有用:

      "useUnknownInCatchVariables": false,

      【讨论】:

      • 这个设置就像一个魅力,非常感谢!
      【解决方案3】:

      您可以使用强制转换:(err as Error)

      我喜欢if 语句解决方案,但这也有效:

      catch (error) {
        let msg = (error as Error).message;
      }
      

      【讨论】:

        【解决方案4】:

        此处解释了 TS 4.0 的问题:https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/#unknown-on-catch

        所有其他答案都对我不起作用,但使用 isAxiosError 工作得很好:

           } catch (error) {
              if (axios.isAxiosError(error)) {
                const errResp = error.response;
                // Handle your error type safe here
              } else {
                // Handle the unknown
              }
            }
        

        没有Object is of type 'unknown'.ts(2571) 错误了。

        【讨论】:

        • 原来的问题没有提到axios,但这正是我所需要的。
        【解决方案5】:

        由于这是您在 google Object is of type 'unknown' 时获得的第一个结果,因此我想发布我的案例。它可能对未来的读者有所帮助。 这不是 OP 问题的答案。

        我在 catch 块中收到此错误。调试了一段时间才知道从typescript v4.0开始,catch子句变量的类型是unknown而不是any。

        并根据docs:

        未知比任何都更安全,因为它提醒我们需要 在对我们的值进行操作之前执行某种类型检查。

        我的代码在 v4.0 之前看起来像这样:

        try {
          // try something exceptional here
        } catch (error) {
          console.log(error.message);
        }
        

        为了修复这个错误,我必须在 error 变量上添加一个额外的 if 检查。

        try {
          // try something exceptional here
        } catch (error) {
          let errorMessage = "Failed to do something exceptional";
          if (error instanceof Error) {
            errorMessage = error.message;
          }
          console.log(errorMessage);
        }
        

        【讨论】:

        • 如果您更新了 Typescript,并且只是希望 linter 停止抱怨......只需明确地执行 catch(error: any) 并根据需要自行缩小范围。我意识到对此有些不满,但我的应用程序有各种 API 库,它们会抛出非常不同的错误对象,我会在找到时间时缩小范围。
        • 简化console.log({ error: err instanceof Error ? err.message : "Failed to do something exceptional" })
        • 如果你有缩小器,使用instanceof Error是否安全?
        • 如果您正在访问错误中存在的某些属性,例如消息,则此方法有效,但是如果我需要访问 fs 抛出的某些属性(例如:err.code),该怎么办?跨度>
        • @BradGreens 如果你这样做,你会得到Catch clause variable cannot have a type annotation
        【解决方案6】:

        像这样向调用函数添加一个类型:

        function(): Observable&lt;any&gt;

        为了避免它返回ig unknown。

        【讨论】:

          【解决方案7】:

          我们需要思考 TS 如何从这个定义中推断出类型。 TS 可以从两个地方理解类型:

          • 显式泛型类型集
          • 函数第二个参数的类型

          在您的用例中,您没有在任何这些地方提供类型,这就是您获得unknown 的原因,因为 TS 如何知道您需要什么参数类型。为了让 TS 有可能理解你可以做的类型或:

          通过以下方式显式设置泛型:

          makeFunction<YourType>((param, options) => {...))
          

          在回调函数中设置类型,例如预先定义一个:

          const f = (a: number, b: {a: string}) => b // here types are set
          makeFunction(f)({a: 'some value'}) // makeFunction is able to infer the types by f
          

          您也可以通过说((param: number, options: MyType)) 内联来执行此操作

          如果options 可以是动态的,请在评论后回答

          我相信你想要以下行为:

          const makeFunction = <F extends (someParam: number, options: any) => any>(callback: F) => {
          
            return (options: Parameters<F>[1]) => {
              const param = 4;
          
              return callback(param, options)  
            }  
          }
          const f = (a: number, b: {a: string}) => b
          makeFunction(f)({ a: 'a' })
          const g = (a: number, b: {b: number}) => b
          makeFunction(g)({b: 1})
          

          我们只说几句话:

          • F 现在是从二进制函数扩展而来的函数,我们直接推断它的类型
          • Parameters&lt;F&gt;[1] 是给定函数 F 类型的第二个参数类型

          【讨论】:

          • 感谢您的回答,但是如果我想要选项作为动态类型呢?它的对象,但对象属性可能不同,这取决于它使用的位置
          【解决方案8】:

          为选项创建一个接口或使用any作为类型,

          makeFunction((param, options: any) => {
          
            const a = options.optionsValue;
          
            })({optionsValue: 'some value'});
          

          Typescript 将选项类型设为 {},这会导致编译期间出现问题。

          【讨论】:

          • 老兄,谢谢——我可以稍后解决这个问题,但天哪,这让我发疯了
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-01-16
          • 2020-10-11
          • 2021-05-06
          • 2020-12-22
          • 2017-09-15
          • 1970-01-01
          • 2021-11-26
          相关资源
          最近更新 更多