1"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([["1726"],{72583(e,n,r){r.r(n),r.d(n,{metadata:()=>t,default:()=>p,frontMatter:()=>c,contentTitle:()=>o,toc:()=>h,assets:()=>u});var t=JSON.parse('{"id":"use-unknown-in-catch-callback-variable","title":"use-unknown-in-catch-callback-variable","description":"Enforce typing arguments in Promise rejection callbacks as `unknown`.","source":"@site/../eslint-plugin/docs/rules/use-unknown-in-catch-callback-variable.mdx","sourceDirName":".","slug":"/use-unknown-in-catch-callback-variable","permalink":"/rules/use-unknown-in-catch-callback-variable","draft":false,"unlisted":false,"editUrl":"https://github.com/typescript-eslint/typescript-eslint/edit/main/packages/website/../eslint-plugin/docs/rules/use-unknown-in-catch-callback-variable.mdx","tags":[],"version":"current","frontMatter":{"description":"Enforce typing arguments in Promise rejection callbacks as `unknown`.","image":"/img/og/rules/use-unknown-in-catch-callback-variable.png"},"sidebar":"rulesSidebar","previous":{"title":"unified-signatures","permalink":"/rules/unified-signatures"}}'),a=r(65723),s=r(7143),i=r(70503),l=r(46742);let c={description:"Enforce typing arguments in Promise rejection callbacks as `unknown`.",image:"/img/og/rules/use-unknown-in-catch-callback-variable.png"},o,u={},h=[{value:"Options",id:"options",level:2},{value:"When Not To Use It",id:"when-not-to-use-it",level:2},{value:"Related To",id:"related-to",level:2},{value:"Resources",id:"resources",level:2}];function d(e){let n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",em:"em",h2:"h2",hr:"hr",li:"li",meta:"meta",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components},{Head:r,RuleAttributes:t,TryInPlayground:c}=n;return r||b("Head",!0),t||b("RuleAttributes",!0),c||b("TryInPlayground",!0),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(a.Fragment,{children:(0,a.jsxs)(n.blockquote,{children:["\n",(0,a.jsxs)(n.p,{children:["Enforce typing arguments in Promise rejection callbacks as ",(0,a.jsx)(n.code,{children:"unknown"}),"."]}),"\n"]})}),"\n",(0,a.jsx)(t,{name:"use-unknown-in-catch-callback-variable"}),"\n","\n",(0,a.jsxs)(n.p,{children:["This rule enforces that you always use the ",(0,a.jsx)(n.code,{children:"unknown"})," type for the parameter of a Promise rejection callback."]}),"\n",(0,a.jsxs)(i.A,{children:[(0,a.jsx)(l.A,{value:"\u274C Incorrect",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-ts",metastring:'eslintrcHash="N4KABGBEBOCuA2BTAzpAXGUEKQAIBcBPABxQGNoBLY-AWhXkoDt8B6WZRW2JgayYD2Adya1mtMgEN8ZABYTJ8eACNJZXrQBukqpOVJ0URNGgDokcGAC+IK0A"',children:"Promise.reject(new Error('I will reject!')).catch(err => {\n console.log(err);\n});\n\nPromise.reject(new Error('I will reject!')).catch((err: any) => {\n console.log(err);\n});\n\nPromise.reject(new Error('I will reject!')).catch((err: Error) => {\n console.log(err);\n});\n\nPromise.reject(new Error('I will reject!')).then(\n result => {\n console.log(result);\n },\n err => {\n console.log(err);\n },\n);\n"})})}),(0,a.jsx)(l.A,{value:"\u2705 Correct",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-ts",metastring:'eslintrcHash="N4KABGBEBOCuA2BTAzpAXGUEKQAIBcBPABxQGNoBLY-AWhXkoDt8B6WZRW2JgayYD2Adya1mtMgEN8ZABYTJ8eACNJZXrQBukqpOVJ0URNGgDokcGAC+IK0A"',children:"Promise.reject(new Error('I will reject!')).catch((err: unknown) => {\n console.log(err);\n});\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["The reason for this rule is to enable programmers to impose constraints on ",(0,a.jsx)(n.code,{children:"Promise"})," error handling analogously to what TypeScript provides for ordinary exception handling."]}),"\n",(0,a.jsxs)(n.p,{children:["For ordinary exceptions, TypeScript treats the ",(0,a.jsx)(n.code,{children:"catch"})," variable as ",(0,a.jsx)(n.code,{children:"any"})," by default. However, ",(0,a.jsx)(n.code,{children:"unknown"})," would be a more accurate type, so TypeScript ",(0,a.jsxs)(n.a,{href:"https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html#defaulting-to-the-unknown-type-in-catch-variables---useunknownincatchvariables",children:["introduced the ",(0,a.jsx)(n.code,{children:"useUnknownInCatchVariables"})," compiler option"]})," to treat the ",(0,a.jsx)(n.code,{children:"catch"})," variable as ",(0,a.jsx)(n.code,{children:"unknown"})," instead."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-ts",children:"try {\n throw x;\n} catch (err) {\n // err has type 'any' with useUnknownInCatchVariables: false\n // err has type 'unknown' with useUnknownInCatchVariables: true\n}\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The Promise analog of the ",(0,a.jsx)(n.code,{children:"try-catch"})," block, ",(0,a.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch",children:(0,a.jsx)(n.code,{children:"Promise.prototype.catch()"})}),", is not affected by the ",(0,a.jsx)(n.code,{children:"useUnknownInCatchVariables"}),' compiler option, and its "',(0,a.jsx)(n.code,{children:"catch"}),' variable" will always have the type ',(0,a.jsx)(n.code,{children:"any"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-ts",children:"Promise.reject(x).catch(err => {\n // err has type 'any' regardless of `useUnknownInCatchVariables`\n});\n"})}),"\n",(0,a.jsxs)(n.p,{children:["However, you can still provide an explicit type annotation, which lets you achieve the same effect as the ",(0,a.jsx)(n.code,{children:"useUnknownInCatchVariables"})," option does for synchronous ",(0,a.jsx)(n.code,{children:"catch"})," variables."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-ts",children:"Promise.reject(x).catch((err: unknown) =>
1 {\n // err has type 'unknown'\n});\n"})}),"\n",(0,a.jsxs)(n.admonition,{type:"info",children:[(0,a.jsxs)(n.p,{children:["There is actually a way to have the ",(0,a.jsx)(n.code,{children:"catch()"})," and ",(0,a.jsx)(n.code,{children:"then()"})," callback variables use the ",(0,a.jsx)(n.code,{children:"unknown"})," type ",(0,a.jsx)(n.em,{children:"without"})," an explicit type annotation at the call sites, but it has the drawback that it involves overriding global type declarations.\nFor example, the library ",(0,a.jsx)(n.a,{href:"https://github.com/uhyo/better-typescript-lib",children:"better-TypeScript-lib"})," sets this up globally for your project (see ",(0,a.jsx)(n.a,{href:"https://github.com/uhyo/better-typescript-lib/blob/c294e177d1cc2b1d1803febf8192a4c83a1fe028/lib/lib.es5.d.ts#L635",children:"the relevant lines in the better-TypeScript-lib source code"})," for details on how)."]}),(0,a.jsxs)(n.p,{children:["For further reading on this, you may also want to look into\n",(0,a.jsx)(n.a,{href:"https://github.com/typescript-eslint/typescript-eslint/issues/7526#issuecomment-1690600813",children:"the discussion in the proposal for this rule"})," and ",(0,a.jsx)(n.a,{href:"https://github.com/microsoft/TypeScript/issues/45602",children:"this TypeScript issue on typing catch callback variables as unknown"}),"."]})]}),"\n",(0,a.jsxs)(i.A,{children:[(0,a.jsx)(l.A,{value:"Flat Config",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",metastring:'title="eslint.config.mjs"',children:'export default defineConfig({\n rules: {\n "@typescript-eslint/use-unknown-in-catch-callback-variable": "error"\n }\n});\n'})})}),(0,a.jsx)(l.A,{value:"Legacy Config",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",metastring:'title=".eslintrc.cjs"',children:'module.exports = {\n "rules": {\n "@typescript-eslint/use-unknown-in-catch-callback-variable": "error"\n }\n};\n'})})})]}),"\n",(0,a.jsx)(c,{eslintrcHash:"N4KABGBEBOCuA2BTAzpAXGUEKQAIBcBPABxQGNoBLY-AWhXkoDt8B6WZRW2JgayYD2Adya1mtMgEN8ZABYTJ8eACNJZXrQBukqpOVJ0URNGgDokcGAC+IK0A",children:(0,a.jsx)(n.p,{children:"Try this rule in the playground \u2197"})}),"\n",(0,a.jsx)(n.h2,{id:"options",children:"Options"}),"\n",(0,a.jsx)(a.Fragment,{children:(0,a.jsx)(n.p,{children:"This rule is not configurable."})}),"\n",(0,a.jsx)(n.h2,{id:"when-not-to-use-it",children:"When Not To Use It"}),"\n",(0,a.jsxs)(n.p,{children:["If your codebase is not yet able to enable ",(0,a.jsx)(n.code,{children:"useUnknownInCatchVariables"}),", it likely would be similarly difficult to enable this rule."]}),"\n",(0,a.jsxs)(n.p,{children:["If you have modified the global type declarations in order to make ",(0,a.jsx)(n.code,{children:"then()"})," and ",(0,a.jsx)(n.code,{children:"catch()"})," callbacks use the ",(0,a.jsx)(n.code,{children:"unknown"})," type without an explicit type annotation, you do not need this rule."]}),"\n",(0,a.jsx)(a.Fragment,{children:(0,a.jsx)(n.hr,{})}),"\n",(0,a.jsx)(a.Fragment,{children:(0,a.jsxs)(n.p,{children:["Type checked lint rules are more powerful than traditional lint rules, but also require configuring ",(0,a.jsx)(n.a,{href:"/getting-started/typed-linting",children:"type checked linting"}),"."]})}),"\n",(0,a.jsx)(a.Fragment,{children:(0,a.jsxs)(n.p,{children:["See ",(0,a.jsx)(n.a,{href:"/troubleshooting/typed-linting/performance",children:"Troubleshooting > Linting with Type Information > Performance"})," if you experience performance degradations after enabling type checked rules."]})}),"\n",(0,a.jsx)(n.h2,{id:"related-to",children:"Related To"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsxs)(n.a,{href:"/blog/avoiding-anys",children:["Avoiding ",(0,a.jsx)(n.code,{children:"any"}),"s with Linting and TypeScript"]})}),"\n"]}),"\n",(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.h2,{id:"resources",children:"Resources"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/rules/use-unknown-in-catch-callback-variable.ts",children:"Rule source"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/tests/rules/use-unknown-in-catch-callback-variable.test.ts",children:"Test source"})}),"\n"]})]}),"\n",(0,a.jsx)(r,{children:(0,a.jsx)(n.meta,{content:"use-unknown-in-catch-callback-variable: Enforce typing arguments in Promise rejection callbacks as unknown",name:"twitter:image:alt"})})]})}function p(e={}){let{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}function b(e,n){throw Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},46742(e,n,r){r.d(n,{A:()=>l});var t=r(65723);r(22155);var a=r(70851),s=r(28226);function i({children:e,className:n,hidden:r}){return(0,t.jsx)("div",{role:"tabpanel",className:(0,a.A)("tabItem_eQ9s",n),hidden:r,children:e})}function l({children:e,className:n,value:r}){let{selectedValue:a,lazy:c}=(0,s.uc)(),o=r===a;return!o&&c?null:(0,t.jsx)(i,{className:n,hidden:!o,children:e})}},70503(e,n,r){r.d(n,{A:()=>d});var t=r(65723);r(22155);var a=r(70851),s=r(98838),i=r(28226),l=r(26309),c=r(29021);function o({className:e}){let{selectedValue:n,selectValue:r,tabValues:s,block:c}=(0,i.uc)(),u=[],{blockElementScrollPositionUntilNextRender:h}=(0,l.a_)(),d=e=>{let t=e.currentTarget,a=s[u.indexOf(t)].value;a!==n&&(h(t),r(a))},p=e=>{let n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{let r=u.indexOf(e.currentTarget)+1;n=u[r]??u[0];break}case"ArrowLeft":{let r=u.indexOf(e.currentTarget)-1;n=u[r]??u[u.length-1]}}n?.focus()};return(0,t.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,a.A)("tabs",{"tabs--block":c},e),children:s.map(({value:e,label:r,attributes:s})=>(0,t.jsx)("li",{role:"tab",tabIndex:n===e?0:-1,"aria-selected":n===e,ref:e=>{u.push(e)},onKeyDown:p,onClick:d,...s,className:(0,a.A)("tabs__item","tabItem_e1w9",s?.className,{"tabs__item--active":n===e}),children:r??e},e))})}function u({children:e}){return(0,t.jsx)("div",{className:"margin-top--md",children:e})}function h({className:e,children:n}){return(0,t.jsxs)("div",{className:(0,a.A)(s.G.tabs.container,"tabs-container","tabList_mVW_"),children:[(0,t.jsx)(o,{className:e}),(0,t.jsx)(u,{children:n})]})}function d(e){let n=(0,c.A)(),r=(0,i.OC)(e);return(0,t.jsx)(i.O_,{value:r,children:(0,t.jsx)(h,{className:e.className,children:(0,i.vT)(e.children)})},String(n))}},28226(e,n,r){r.d(n,{OC:()=>d,O_:()=>m,uc:()=>b,vT:()=>u});var t=r(65723),a=r(22155),s=r(62934),i=r(24127),l=r(12910),c=r(22399),o=r(6660);function u(e){return a.Children.toArray(e).filter(e=>"\n"!==e)}function h({value:e,tabValues:n}){return n.some(n=>n.value===e)}function d(e){let n,{defaultValue:r,queryString:t=!1,groupId:u}=e,d=function(e){let{values:n,children:r}=e;return(0,a.useMemo)(()=>{let e=n??a.Children.toArray(r).flatMap(e=>{if(!e)return[];if((0,a.isValidElement)(e)&&function(e){let{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return[e];
1let n="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${n}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop. 2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:n,attributes:r,default:t}})=>({value:e,label:n,attributes:r,default:t})),t=(0,c.XI)(e,(e,n)=>e.value===n.value);if(t.length>0)throw Error(`Docusaurus error: Duplicate values "${t.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[n,r])}(e),[p,b]=(0,a.useState)(()=>(function({defaultValue:e,tabValues:n}){if(0===n.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!h({value:e,tabValues:n}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${n.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let r=n.find(e=>e.default)??n[0];if(!r)throw Error("Unexpected error: 0 tabValues");return r.value})({defaultValue:r,tabValues:d})),[m,f]=function({queryString:e=!1,groupId:n}){let r=(0,s.W6)(),t=function({queryString:e=!1,groupId:n}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!n)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:e,groupId:n});return[(0,l.aZ)(t),(0,a.useCallback)(e=>{if(!t)return;let n=new URLSearchParams(r.location.search);n.set(t,e),r.replace({...r.location,search:n.toString()})},[t,r])]}({queryString:t,groupId:u}),[x,g]=function({groupId:e}){let n=e?`docusaurus.tab.${e}`:null,[r,t]=(0,o.Dv)(n);return[r,(0,a.useCallback)(e=>{n&&t.set(e)},[n,t])]}({groupId:u}),j=h({value:n=m??x,tabValues:d})?n:null;return(0,i.A)(()=>{j&&b(j)},[j]),{selectedValue:p,selectValue:(0,a.useCallback)(e=>{if(!h({value:e,tabValues:d}))throw Error(`Can't select invalid tab value=${e}`);b(e),f(e),g(e)},[f,g,d]),tabValues:d,lazy:e.lazy??!1,block:e.block??!1}}let p=(0,a.createContext)(null);function b(){let e=a.useContext(p);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function m(e){return(0,t.jsx)(p.Provider,{value:e.value,children:e.children})}},7143(e,n,r){r.d(n,{R:()=>i,x:()=>l});var t=r(22155);let a={},s=t.createContext(a);function i(e){let n=t.useContext(s);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.