diff --git a/src/rules/typedefRule.ts b/src/rules/typedefRule.ts index 778e3000309..103efc1885c 100644 --- a/src/rules/typedefRule.ts +++ b/src/rules/typedefRule.ts @@ -29,6 +29,7 @@ interface Options { "arrow-parameter"?: boolean; "property-declaration"?: boolean; "variable-declaration"?: boolean; + "variable-declaration-ignore-function"?: boolean; "member-variable-declaration"?: boolean; "object-destructuring"?: boolean; "array-destructuring"?: boolean; @@ -41,6 +42,7 @@ const OPTION_PARAMETER: Option = "parameter"; const OPTION_ARROW_PARAMETER: Option = "arrow-parameter"; const OPTION_PROPERTY_DECLARATION: Option = "property-declaration"; const OPTION_VARIABLE_DECLARATION: Option = "variable-declaration"; +const OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION: Option = "variable-declaration-ignore-function"; const OPTION_MEMBER_VARIABLE_DECLARATION: Option = "member-variable-declaration"; const OPTION_OBJECT_DESTRUCTURING: Option = "object-destructuring"; const OPTION_ARRAY_DESTRUCTURING: Option = "array-destructuring"; @@ -67,6 +69,7 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"${OPTION_ARROW_PARAMETER}"\` checks type specifier of function parameters for arrow functions. * \`"${OPTION_PROPERTY_DECLARATION}"\` checks return types of interface properties. * \`"${OPTION_VARIABLE_DECLARATION}"\` checks non-binding variable declarations. + * \`"${OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION}"\` ignore variable declarations for non-arrow and arrow functions. * \`"${OPTION_MEMBER_VARIABLE_DECLARATION}"\` checks member variable declarations. * \`"${OPTION_OBJECT_DESTRUCTURING}"\` checks object destructuring declarations. * \`"${OPTION_ARRAY_DESTRUCTURING}"\` checks array destructuring declarations.`, @@ -81,13 +84,14 @@ export class Rule extends Lint.Rules.AbstractRule { OPTION_ARROW_PARAMETER, OPTION_PROPERTY_DECLARATION, OPTION_VARIABLE_DECLARATION, + OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION, OPTION_MEMBER_VARIABLE_DECLARATION, OPTION_OBJECT_DESTRUCTURING, OPTION_ARRAY_DESTRUCTURING, ], }, minLength: 0, - maxLength: 7, + maxLength: 10, }, optionExamples: [ [true, OPTION_CALL_SIGNATURE, OPTION_PARAMETER, OPTION_MEMBER_VARIABLE_DECLARATION], @@ -153,7 +157,8 @@ class TypedefWalker extends Lint.AbstractWalker { } } - private checkParameter({ parent, name, type }: ts.ParameterDeclaration): void { + private checkParameter(node: ts.Node): void { + const { parent, name, type } = node as ts.ParameterDeclaration; const isArrowFunction = parent.kind === ts.SyntaxKind.ArrowFunction; const option = (() => { @@ -177,11 +182,20 @@ class TypedefWalker extends Lint.AbstractWalker { // If this is an arrow function, it doesn't need to have a typedef on the property declaration // as the typedefs can be on the function's parameters instead if (initializer === undefined || initializer.kind !== ts.SyntaxKind.ArrowFunction) { + if ( + this.options[OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION] === true && + initializer !== undefined && + initializer.kind === ts.SyntaxKind.FunctionExpression + ) { + return; + } this.checkTypeAnnotation("member-variable-declaration", name, type, name); } } - private checkVariableDeclaration({ parent, name, type }: ts.VariableDeclaration): void { + private checkVariableDeclaration(node: ts.Node): void { + const { parent, name, type } = node as ts.VariableDeclaration; + // variable declarations should always have a grandparent, but check that to be on the safe side. // catch statements will be the parent of the variable declaration // for-in/for-of loops will be the gradparent of the variable declaration @@ -193,20 +207,39 @@ class TypedefWalker extends Lint.AbstractWalker { return; } - const option = (() => { - switch (name.kind) { - case ts.SyntaxKind.ObjectBindingPattern: - return "object-destructuring"; - case ts.SyntaxKind.ArrayBindingPattern: - return "array-destructuring"; - default: - return "variable-declaration"; - } - })(); + let option: Option; + + switch (name.kind) { + case ts.SyntaxKind.ObjectBindingPattern: + option = OPTION_OBJECT_DESTRUCTURING; + break; + + case ts.SyntaxKind.ArrayBindingPattern: + option = OPTION_ARRAY_DESTRUCTURING; + break; + + default: + option = OPTION_VARIABLE_DECLARATION; + } + + if (this.shouldIgnoreVariableDeclaration(node)) { + return; + } this.checkTypeAnnotation(option, name, type, name); } + private shouldIgnoreVariableDeclaration(node: ts.Node): boolean { + const ignoreFunctions: boolean = + this.options[OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION] === true; + + return ( + ignoreFunctions && + (utils.getChildOfKind(node, ts.SyntaxKind.ArrowFunction) !== undefined || + utils.getChildOfKind(node, ts.SyntaxKind.FunctionExpression) !== undefined) + ); + } + private checkTypeAnnotation( option: Option, location: ts.Node | ts.NodeArray, diff --git a/test/rules/typedef/variable-declaration-ignore-function/test.ts.lint b/test/rules/typedef/variable-declaration-ignore-function/test.ts.lint new file mode 100644 index 00000000000..d9f013a93a0 --- /dev/null +++ b/test/rules/typedef/variable-declaration-ignore-function/test.ts.lint @@ -0,0 +1,23 @@ +var foo = function(): void {}; +let foo = function(): void {}; +const foo = function(): void {}; + +var foo = (): void => {}; +let foo = (): void => {}; +const foo = (): void => {}; + +class Foo { + foo = (): void => {}; + foo = function(): void {}; +} + +const foo: () => void = (): void => {}; +const foo: () => void = function(): void {}; + +var noTypeDef = 'Should still fail'; + ~~~~~~~~~ [expected variable-declaration: 'noTypeDef' to have a typedef] + +class NoTypeDef { + public noTypeDef = 'Should still fail'; + ~~~~~~~~~ [expected member-variable-declaration: 'noTypeDef' to have a typedef] +} diff --git a/test/rules/typedef/variable-declaration-ignore-function/tslint.json b/test/rules/typedef/variable-declaration-ignore-function/tslint.json new file mode 100644 index 00000000000..f815790c07b --- /dev/null +++ b/test/rules/typedef/variable-declaration-ignore-function/tslint.json @@ -0,0 +1,10 @@ +{ + "rules": { + "typedef": [ + true, + "variable-declaration", + "member-variable-declaration", + "variable-declaration-ignore-function" + ] + } +}