Back to Biomejs

noUnsafeDeclarationMerging

src/content/docs/linter/rules/no-unsafe-declaration-merging.mdx

latest4.0 KB
Original Source

import { Tabs, TabItem } from '@astrojs/starlight/components';

<Tabs> <TabItem label="TypeScript and TSX" icon="seti:typescript"> ## Summary - Rule available since: `v1.0.0` - Diagnostic Category: [`lint/suspicious/noUnsafeDeclarationMerging`](/reference/diagnostics#diagnostic-category) - This rule is **recommended**, meaning it is enabled by default. - This rule doesn't have a fix. - The default severity of this rule is [**error**](/reference/diagnostics#error). - Sources: - Same as [`@typescript-eslint/no-unsafe-declaration-merging`](https://typescript-eslint.io/rules/no-unsafe-declaration-merging)

How to configure

json
{
	"linter": {
		"rules": {
			"suspicious": {
				"noUnsafeDeclarationMerging": "error"
			}
		}
	}
}

Description

Disallow unsafe declaration merging between interfaces and classes.

TypeScript's declaration merging supports merging separate declarations with the same name.

Declaration merging between classes and interfaces is unsafe. The TypeScript Compiler doesn't check whether properties defined in the interface are initialized in the class. This can cause lead to TypeScript not detecting code that will cause runtime errors.

Examples

Invalid

ts
interface Foo {
    f(): void
}

class Foo {}

const foo = new Foo();
foo.f(); // Runtime Error: Cannot read properties of undefined.
<pre class="language-text"><code class="language-text">code-block.ts:5:7 <a href="https://biomejs.dev/linter/rules/no-unsafe-declaration-merging">lint/suspicious/noUnsafeDeclarationMerging</a> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ <strong><span style="color: Tomato;">✖</span></strong> <span style="color: Tomato;">This </span><span style="color: Tomato;"><strong>class</strong></span><span style="color: Tomato;"> is unsafely merged with an </span><span style="color: Tomato;"><strong>interface</strong></span><span style="color: Tomato;">.</span> <strong>3 │ </strong>&#125; <strong>4 │ </strong> <strong><span style="color: Tomato;">&gt;</span></strong> <strong>5 │ </strong>class Foo &#123;&#125; <strong> │ </strong> <strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong> <strong>6 │ </strong> <strong>7 │ </strong>const foo = new Foo(); <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">The </span><span style="color: lightgreen;"><strong>interface</strong></span><span style="color: lightgreen;"> is declared here.</span> <strong><span style="color: Tomato;">&gt;</span></strong> <strong>1 │ </strong>interface Foo &#123; <strong> │ </strong> <strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong> <strong>2 │ </strong> f(): void <strong>3 │ </strong>&#125; <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">The TypeScript compiler doesn't check whether properties defined in the interface are initialized in the class.</span> </code></pre>

Valid

ts
interface Foo {}
class Bar implements Foo {}
ts
namespace Baz {}
namespace Baz {}
enum Baz {}
</TabItem> </Tabs>