Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Commit

Permalink
Add no-interface-constructor rule
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-hanson committed Jan 2, 2017
1 parent d6e3f29 commit 4c3c188
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 0 deletions.
12 changes: 12 additions & 0 deletions docs/_data/rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,18 @@
"typescriptOnly": true,
"requiresTypeInfo": true
},
{
"ruleName": "no-interface-constructor",
"description": "Warns on apparent attempts to define constructors for interfaces.",
"rationale": "`interface I { new(): I }` declares a type where for `x: I`, `new x()` is also of type `I`.",
"optionsDescription": "Not configurable.",
"options": null,
"optionExamples": [
"true"
],
"type": "functionality",
"typescriptOnly": true
},
{
"ruleName": "no-internal-module",
"description": "Disallows internal `module`",
Expand Down
14 changes: 14 additions & 0 deletions docs/rules/no-interface-constructor/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
ruleName: no-interface-constructor
description: Warns on apparent attempts to define constructors for interfaces.
rationale: '`interface I { new(): I }` declares a type where for `x: I`, `new x()` is also of type `I`.'
optionsDescription: Not configurable.
options: null
optionExamples:
- 'true'
type: functionality
typescriptOnly: true
layout: rule
title: 'Rule: no-interface-constructor'
optionsJSON: 'null'
---
60 changes: 60 additions & 0 deletions src/rules/noInterfaceConstructorRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* @license
* Copyright 2017 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as ts from "typescript";

import * as Lint from "../index";

export class Rule extends Lint.Rules.AbstractRule {
/* tslint:disable:object-literal-sort-keys */
public static metadata: Lint.IRuleMetadata = {
ruleName: "no-interface-constructor",
description: "Warns on apparent attempts to define constructors for interfaces.",
rationale: "`interface I { new(): I }` declares a type where for `x: I`, `new x()` is also of type `I`.",
optionsDescription: "Not configurable.",
options: null,
optionExamples: ["true"],
type: "functionality",
typescriptOnly: true,
};
/* tslint:enable:object-literal-sort-keys */

public static FAILURE_STRING = "Interfaces cannot be constructed, only classes. Did you mean `declare class`?";

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new Walker(sourceFile, this.getOptions()));
}
}

class Walker extends Lint.RuleWalker {
public visitConstructSignature(node: ts.ConstructSignatureDeclaration) {
const iface = node.parent as ts.InterfaceDeclaration;
if (iface.kind !== ts.SyntaxKind.InterfaceDeclaration) {
return;
}

const name = iface.name.text;
if (node.type.kind !== ts.SyntaxKind.TypeReference) {
return;
}

const typeName = (node.type as ts.TypeReferenceNode).typeName;
if (typeName.kind === ts.SyntaxKind.Identifier && (typeName as ts.Identifier).text === name) {
this.addFailureAtNode(node, Rule.FAILURE_STRING);
}
}
}
22 changes: 22 additions & 0 deletions test/rules/no-interface-constructor/test.ts.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
interface I {
new(): I;
~~~~~~~~~ [0]
}

// Works for generic type.
interface G {
new<T>(): G<T>;
~~~~~~~~~~~~~~~ [0]
}

// OK if return type is not the interface.
interface J {
new(): I;
}

// OK in type literal.
type T = {
new(): T;
}

[0]: Interfaces cannot be constructed, only classes. Did you mean `declare class`?
5 changes: 5 additions & 0 deletions test/rules/no-interface-constructor/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-interface-constructor": true
}
}

0 comments on commit 4c3c188

Please sign in to comment.