๐ `noConfusingVoidType` shouldn't report for `void | never`
Opened this issue ยท 0 comments
Environment information
CLI:
Version: 1.9.5-nightly.ff02a0b
Color support: true
Platform:
CPU Architecture: x86_64
OS: windows
Environment:
BIOME_LOG_PATH: unset
BIOME_LOG_PREFIX_NAME: unset
BIOME_CONFIG_PATH: unset
NO_COLOR: unset
TERM: unset
JS_RUNTIME_VERSION: "v22.9.0"
JS_RUNTIME_NAME: "node"
NODE_PACKAGE_MANAGER: unset
Biome Configuration:
Status: Loaded successfully
Formatter disabled: false
Linter disabled: false
Organize imports disabled: false
VCS disabled: true
Linter:
JavaScript enabled: true
JSON enabled: true
CSS enabled: true
GraphQL enabled: false
Recommended: false
All: false
Enabled rules:
a11y/noAccessKey
a11y/noAriaHiddenOnFocusable
a11y/noAriaUnsupportedElements
a11y/noAutofocus
a11y/noBlankTarget
a11y/noDistractingElements
a11y/noHeaderScope
a11y/noInteractiveElementToNoninteractiveRole
a11y/noLabelWithoutControl
a11y/noNoninteractiveElementToInteractiveRole
a11y/noNoninteractiveTabindex
a11y/noPositiveTabindex
a11y/noRedundantAlt
a11y/noRedundantRoles
a11y/noSvgWithoutTitle
a11y/useAltText
a11y/useAnchorContent
a11y/useAriaActivedescendantWithTabindex
a11y/useAriaPropsForRole
a11y/useButtonType
a11y/useFocusableInteractive
a11y/useGenericFontNames
a11y/useHeadingContent
a11y/useHtmlLang
a11y/useIframeTitle
a11y/useKeyWithClickEvents
a11y/useKeyWithMouseEvents
a11y/useMediaCaption
a11y/useSemanticElements
a11y/useValidAnchor
a11y/useValidAriaProps
a11y/useValidAriaRole
a11y/useValidAriaValues
a11y/useValidLang
complexity/noBannedTypes
complexity/noEmptyTypeParameters
complexity/noExcessiveNestedTestSuites
complexity/noExtraBooleanCast
complexity/noForEach
complexity/noMultipleSpacesInRegularExpressionLiterals
complexity/noStaticOnlyClass
complexity/noThisInStatic
complexity/noUselessCatch
complexity/noUselessConstructor
complexity/noUselessEmptyExport
complexity/noUselessFragments
complexity/noUselessLabel
complexity/noUselessLoneBlockStatements
complexity/noUselessRename
complexity/noUselessSwitchCase
complexity/noUselessTernary
complexity/noUselessThisAlias
complexity/noUselessTypeConstraint
complexity/noWith
complexity/useArrowFunction
complexity/useFlatMap
complexity/useLiteralKeys
complexity/useOptionalChain
complexity/useRegexLiterals
complexity/useSimpleNumberKeys
correctness/noChildrenProp
correctness/noConstAssign
correctness/noConstantCondition
correctness/noConstructorReturn
correctness/noEmptyCharacterClassInRegex
correctness/noEmptyPattern
correctness/noFlatMapIdentity
correctness/noGlobalObjectCalls
correctness/noInnerDeclarations
correctness/noInvalidBuiltinInstantiation
correctness/noInvalidConstructorSuper
correctness/noInvalidDirectionInLinearGradient
correctness/noInvalidGridAreas
correctness/noInvalidPositionAtImportRule
correctness/noInvalidUseBeforeDeclaration
correctness/noNonoctalDecimalEscape
correctness/noPrecisionLoss
correctness/noRenderReturnValue
correctness/noSelfAssign
correctness/noSetterReturn
correctness/noStringCaseMismatch
correctness/noSwitchDeclarations
correctness/noUnknownFunction
correctness/noUnknownMediaFeatureName
correctness/noUnknownProperty
correctness/noUnknownUnit
correctness/noUnmatchableAnbSelector
correctness/noUnnecessaryContinue
correctness/noUnreachable
correctness/noUnreachableSuper
correctness/noUnsafeFinally
correctness/noUnsafeOptionalChaining
correctness/noUnusedLabels
correctness/noVoidElementsWithChildren
correctness/noVoidTypeReturn
correctness/useExhaustiveDependencies
correctness/useIsNan
correctness/useJsxKeyInIterable
correctness/useValidForDirection
correctness/useYield
performance/noAccumulatingSpread
performance/noDelete
security/noDangerouslySetInnerHtml
security/noDangerouslySetInnerHtmlWithChildren
security/noGlobalEval
style/noArguments
style/noCommaOperator
style/noInferrableTypes
style/noNonNullAssertion
style/noParameterAssign
style/noUnusedTemplateLiteral
style/noUselessElse
style/noVar
style/useAsConstAssertion
style/useConst
style/useDefaultParameterLast
style/useEnumInitializers
style/useExponentiationOperator
style/useExportType
style/useImportType
style/useLiteralEnumMembers
style/useNodejsImportProtocol
style/useNumberNamespace
style/useNumericLiterals
style/useSelfClosingElements
style/useShorthandFunctionType
style/useSingleVarDeclarator
style/useTemplate
style/useWhile
suspicious/noApproximativeNumericConstant
suspicious/noArrayIndexKey
suspicious/noAssignInExpressions
suspicious/noAsyncPromiseExecutor
suspicious/noCatchAssign
suspicious/noClassAssign
suspicious/noCommentText
suspicious/noCompareNegZero
suspicious/noConfusingLabels
suspicious/noConfusingVoidType
suspicious/noConstEnum
suspicious/noControlCharactersInRegex
suspicious/noDebugger
suspicious/noDoubleEquals
suspicious/noDuplicateAtImportRules
suspicious/noDuplicateCase
suspicious/noDuplicateClassMembers
suspicious/noDuplicateFontNames
suspicious/noDuplicateJsxProps
suspicious/noDuplicateObjectKeys
suspicious/noDuplicateParameters
suspicious/noDuplicateSelectorsKeyframeBlock
suspicious/noDuplicateTestHooks
suspicious/noEmptyBlock
suspicious/noEmptyInterface
suspicious/noExplicitAny
suspicious/noExportsInTest
suspicious/noExtraNonNullAssertion
suspicious/noFallthroughSwitchClause
suspicious/noFocusedTests
suspicious/noFunctionAssign
suspicious/noGlobalAssign
suspicious/noGlobalIsFinite
suspicious/noGlobalIsNan
suspicious/noImplicitAnyLet
suspicious/noImportAssign
suspicious/noImportantInKeyframe
suspicious/noLabelVar
suspicious/noMisleadingCharacterClass
suspicious/noMisleadingInstantiator
suspicious/noMisrefactoredShorthandAssign
suspicious/noPrototypeBuiltins
suspicious/noRedeclare
suspicious/noRedundantUseStrict
suspicious/noSelfCompare
suspicious/noShadowRestrictedNames
suspicious/noShorthandPropertyOverrides
suspicious/noSparseArray
suspicious/noSuspiciousSemicolonInJsx
suspicious/noThenProperty
suspicious/noUnsafeDeclarationMerging
suspicious/noUnsafeNegation
suspicious/useDefaultSwitchClauseLast
suspicious/useGetterReturn
suspicious/useIsArray
suspicious/useNamespaceKeyword
suspicious/useValidTypeof
Workspace:
Open Documents: 0
Rule name
lint/suspicious/noConfusingVoidType
Playground link
Expected result
The noConfusingVoidType
rule is triggering a false positive for the following pattern:
function throwAnError(): void | never {
throw new Error("This function might throw an error.")
}
Technical Justification
This should be considered valid TypeScript code for the following reasons:
-
The
never
type in TypeScript explicitly indicates that a function will not return normally (e.g., it will throw an error or enter an infinite loop) -
TypeScript requires a union type with
never
to avoid error TS2534:TS2534: A function returning never cannot have a reachable end point.
-
The
void | never
union is semantically meaningful here because:void
indicates the function returns nothing when successfulnever
indicates the function will throw (never return) on invalid input
-
This pattern is commonly used in TypeScript codebases for functions that either:
- Complete successfully returning nothing (
void
) - Throw an error (
never
)
- Complete successfully returning nothing (
Current Behavior
If we specify only never
as the return type:
function throwAnError(): never {
throw new Error("This function might throw an error.")
}
TypeScript will raise error TS2534, requiring us to use a union type. Since the function doesn't return any value (only throws on invalid input), void | never
is the appropriate type union.
Proposed Resolution
The noConfusingVoidType
rule should be updated to allow void | never
unions specifically when:
- The function body contains a
throw
statement - The
never
type is used to indicate error throwing behavior
This would align with TypeScript's type system design and common error handling patterns in the ecosystem.
Additional Context
This pattern is particularly useful for:
- Input validation functions
- Guard clauses
- Error boundary functions
- Type narrowing functions
The use of void | never
clearly communicates to developers that they should handle potential errors using try-catch blocks, making the code more maintainable and type-safe.
Code of Conduct
- I agree to follow Biome's Code of Conduct