ウェブサイト検索

オブジェクトは 'unknown' 型の TypeScript ジェネリクスです


私は、関数を引数として取り、新しい関数を返す単純な関数を持っています。返された関数を呼び出すときに、Object is of type 'unknown' が発生します

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

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

    return callback(param, options)  
  }  
}

上のコードはTypeScriptでは問題ありませんが、関数を呼び出すときに不具合が発生します

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

回答 #1

これは、GoogleでObject is of type 'unknown'を検索したときに最初に出る結果なので、私のケースを投稿したいと思います。将来の読者の役に立つかもしれません。これはOPの質問への答えではありません。

私はこのエラーを catch ブロックで受け取りました。しばらくデバッグした後、TypeScript v4.0 以降、catch 句の変数は any ではなく unknown 型になることが分かりました。

そして、ドキュメントによると:

unknown はどの型よりも安全です。なぜなら、それは私たちに値を操作する前に何らかの型チェックを行う必要があることを思い出させてくれるからです。

私のコードは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);
}

回答 #2

次のようにtsconfig.jsonを更新することで、私にはうまくいきました:

"useUnknownInCatchVariables": false,

更新:

これを compilerOptions の下にこのように置く必要があります

"compilerOptions": {
    "useUnknownInCatchVariables": false
  }

注意: このコンパイラオプションを使用するには、TypeScript v4.4以上が必要です。そうでないとコンパイルエラーが発生します。

npm install -g ts-node@latest

npm install -g typescript@latest

回答 #3

私は TypeScript をバージョン 4.4 にアップデートした際に try/catch でこの問題が発生し、ドキュメントでその説明を見つけました。

要約すると、履歴書には、strict が有効な場合デフォルトで true となるフラグ useUnknownInCatchVariables が追加されました。これは基本的に、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
    }
}

回答 #4

キャスティングを使用できます: (err as Error)

私はif文の解決策が好きですが、これも動作します:

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

回答 #5

私たちは、TSがこの定義から型をどのように推論できるかを考える必要があります。TSは2つの場所から型を理解することができます:

  • 明示的なジェネリック型セット
  • 関数の第二引数の型

あなたのユースケースでは、これらのどの場所にも型を提供していません。そしてこれが、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<F>[1] は、与えられた関数 F の2番目の引数の型です

回答 #6

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 は型 'unknown' です。ts(2571) エラーは発生しません。

関連記事