diff --git a/.changeset/plain-chairs-tie.md b/.changeset/plain-chairs-tie.md
new file mode 100644
index 000000000..5b5c46d5d
--- /dev/null
+++ b/.changeset/plain-chairs-tie.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-svelte': patch
+---
+
+fix: correct detection of externally defined types in `no-unused-props` rule
diff --git a/packages/eslint-plugin-svelte/src/rules/no-unused-props.ts b/packages/eslint-plugin-svelte/src/rules/no-unused-props.ts
index 0d057b3f0..d425026f2 100644
--- a/packages/eslint-plugin-svelte/src/rules/no-unused-props.ts
+++ b/packages/eslint-plugin-svelte/src/rules/no-unused-props.ts
@@ -80,15 +80,11 @@ export default createRule('no-unused-props', {
return shouldIgnore(typeStr) || (symbolName ? shouldIgnore(symbolName) : false);
}
- function isExternalType(type: ts.Type): boolean {
- const symbol = type.getSymbol();
- if (!symbol) return false;
-
+ function isInternalProperty(symbol: ts.Symbol): boolean {
const declarations = symbol.getDeclarations();
if (!declarations || declarations.length === 0) return false;
- const sourceFile = declarations[0].getSourceFile();
- return sourceFile.fileName !== fileName;
+ return declarations.every((decl) => decl.getSourceFile().fileName === fileName);
}
/**
@@ -200,7 +196,6 @@ export default createRule('no-unused-props', {
if (checkedTypes.has(typeStr)) return;
checkedTypes.add(typeStr);
if (shouldIgnoreType(type)) return;
- if (!checkImportedTypes && isExternalType(type)) return;
const properties = typeChecker.getPropertiesOfType(type);
const baseTypes = type.getBaseTypes();
@@ -225,6 +220,7 @@ export default createRule('no-unused-props', {
for (const prop of properties) {
if (isBuiltInProperty(prop)) continue;
+ if (!checkImportedTypes && !isInternalProperty(prop)) continue;
const propName = prop.getName();
const currentPath = [...parentPath, propName];
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/ignore-external-type-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/ignore-external-type-errors.yaml
new file mode 100644
index 000000000..502c15458
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/ignore-external-type-errors.yaml
@@ -0,0 +1,4 @@
+- message: "'child2' is an unused Props property."
+ line: 9
+ column: 6
+ suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/ignore-external-type-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/ignore-external-type-input.svelte
new file mode 100644
index 000000000..2d26bd2d9
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/ignore-external-type-input.svelte
@@ -0,0 +1,10 @@
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/imported-type-check-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/imported-type-check-errors.yaml
index 2f341476f..278805b2d 100644
--- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/imported-type-check-errors.yaml
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/imported-type-check-errors.yaml
@@ -1,6 +1,4 @@
- message: "'name' is an unused Props property."
line: 6
column: 6
- endLine: 6
- endColumn: 20
suggestions: null
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/shared-types.ts b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/shared-types.ts
index a60e61ef1..e33a3a24e 100644
--- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/shared-types.ts
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/shared-types.ts
@@ -1,3 +1,14 @@
export interface BaseProps {
name: string;
}
+
+export interface FooDTO {
+ foo: string;
+ bar: number;
+ baz: BazDTO;
+}
+
+interface BazDTO {
+ qux: string;
+ quux: number;
+}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/ignore-external-type-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/ignore-external-type-input.svelte
new file mode 100644
index 000000000..920dece77
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/ignore-external-type-input.svelte
@@ -0,0 +1,10 @@
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/shared-types.ts b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/shared-types.ts
index a60e61ef1..e33a3a24e 100644
--- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/shared-types.ts
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/shared-types.ts
@@ -1,3 +1,14 @@
export interface BaseProps {
name: string;
}
+
+export interface FooDTO {
+ foo: string;
+ bar: number;
+ baz: BazDTO;
+}
+
+interface BazDTO {
+ qux: string;
+ quux: number;
+}