@ CheckReturnValue private FlowScope traverseCatch ( Node catchNode , FlowScope scope ) { Node catchTarget = catchNode . getFirstChild ( ) ; if ( catchTarget . isName ( ) ) { // TODO(lharker): is this case even necessary? seems like TypedScopeCreator handles it Node name = catchNode . getFirstChild ( ) ; JSType type ; // If the catch expression name was declared in the catch use that type, // otherwise use "unknown". JSDocInfo info = name . getJSDocInfo ( ) ; if ( info != null && info . hasType ( ) ) { type = info . getType ( ) . evaluate ( scope . getDeclarationScope ( ) , registry ) ; } else { type = getNativeType ( JSTypeNative . UNKNOWN_TYPE ) ; } name . setJSType ( type ) ; return redeclareSimpleVar ( scope , name , type ) ; } else if ( catchTarget . isDestructuringPattern ( ) ) { Node pattern = catchNode . getFirstChild ( ) ; return traverseDestructuringPattern ( pattern , scope , unknownType , AssignmentType . DECLARATION ) ; } else { checkState ( catchTarget . isEmpty ( ) , catchTarget ) ; // ES2019 allows `try {} catch {}` with no catch expression return scope ; } }
Any value can be thrown so it s really impossible to determine the type of a CATCH param . Treat it as the UNKNOWN type .