From 3c5659b1984c6eeb07e4e06d9a213d0daca96e48 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 12 Jan 2020 16:01:45 -0800 Subject: [PATCH] fix(eslint-plugin): [no-unnec-type-assert] handle JSX attributes (#1002) Co-authored-by: Armano --- .../rules/no-unnecessary-type-assertion.ts | 3 ++ packages/eslint-plugin/tests/RuleTester.ts | 1 + .../eslint-plugin/tests/fixtures/react.tsx | 0 .../tests/fixtures/tsconfig.json | 7 +++- .../no-unnecessary-type-assertion.test.ts | 41 +++++++++++++++++++ 5 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 packages/eslint-plugin/tests/fixtures/react.tsx diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts index f0ed2502bb8..943beb459d7 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts @@ -1,6 +1,7 @@ import { TSESTree } from '@typescript-eslint/experimental-utils'; import { isCallExpression, + isJsxExpression, isNewExpression, isObjectType, isObjectFlagSet, @@ -117,6 +118,8 @@ export default util.createRule({ return parent.type ? checker.getTypeFromTypeNode(parent.type) : undefined; + } else if (isJsxExpression(parent)) { + return checker.getContextualType(parent); } else if ( ![ts.SyntaxKind.TemplateSpan, ts.SyntaxKind.JsxExpression].includes( parent.kind, diff --git a/packages/eslint-plugin/tests/RuleTester.ts b/packages/eslint-plugin/tests/RuleTester.ts index 7d8bdb2c695..c650c83449c 100644 --- a/packages/eslint-plugin/tests/RuleTester.ts +++ b/packages/eslint-plugin/tests/RuleTester.ts @@ -44,6 +44,7 @@ class RuleTester extends TSESLint.RuleTester { ): void { const errorMessage = `Do not set the parser at the test level unless you want to use a parser other than ${parser}`; + // standardize the valid tests as objects tests.valid = tests.valid.map(test => { if (typeof test === 'string') { return { diff --git a/packages/eslint-plugin/tests/fixtures/react.tsx b/packages/eslint-plugin/tests/fixtures/react.tsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/eslint-plugin/tests/fixtures/tsconfig.json b/packages/eslint-plugin/tests/fixtures/tsconfig.json index 92694993c53..7ff53268e42 100644 --- a/packages/eslint-plugin/tests/fixtures/tsconfig.json +++ b/packages/eslint-plugin/tests/fixtures/tsconfig.json @@ -1,10 +1,15 @@ { "compilerOptions": { + "jsx": "preserve", "target": "es5", "module": "commonjs", "strict": true, "esModuleInterop": true, "lib": ["es2015", "es2017", "esnext"], "experimentalDecorators": true - } + }, + "include": [ + "file.ts", + "react.tsx" + ] } diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts index b4f079f3960..595d1961932 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts @@ -117,6 +117,19 @@ function testFunction(_param: string | null): void { /* noop */ } const value = 'test' as string | null | undefined testFunction(value!) `, + // https://github.com/typescript-eslint/typescript-eslint/issues/982 + { + code: ` +declare namespace JSX { interface IntrinsicElements { div: { key?: string | number } } } + +function Test(props: { + id?: null | string | number; +}) { + return
; +} + `, + filename: path.join(rootDir, 'react.tsx'), + }, ], invalid: [ @@ -327,5 +340,33 @@ class Mx { }, ], }, + // https://github.com/typescript-eslint/typescript-eslint/issues/982 + { + code: ` +declare namespace JSX { interface IntrinsicElements { div: { key?: string | number } } } + +function Test(props: { + id?: string | number; +}) { + return
; +} + `, + output: ` +declare namespace JSX { interface IntrinsicElements { div: { key?: string | number } } } + +function Test(props: { + id?: string | number; +}) { + return
; +} + `, + errors: [ + { + messageId: 'contextuallyUnnecessary', + line: 7, + }, + ], + filename: path.join(rootDir, 'react.tsx'), + }, ], });