From 27ccc49a5ab596f911105d4c983403c236b9ed2a Mon Sep 17 00:00:00 2001 From: Dimitri B Date: Thu, 27 May 2021 19:12:41 +0200 Subject: [PATCH] Allow `expectError` assertions to detect non-callable/non-constructable values/expressions (#104) --- source/lib/compiler.ts | 7 ++++++- source/lib/interfaces.ts | 9 +++++++-- .../values-disabled-no-implicit-any/index.d.ts | 1 + .../values-disabled-no-implicit-any/index.js | 3 +++ .../values-disabled-no-implicit-any/index.test-d.ts | 5 +++++ .../values-disabled-no-implicit-any/package.json | 8 ++++++++ source/test/fixtures/expect-error/values/index.d.ts | 2 ++ .../test/fixtures/expect-error/values/index.test-d.ts | 11 ++++++++++- source/test/test.ts | 6 ++++++ 9 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.d.ts create mode 100644 source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.js create mode 100644 source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.test-d.ts create mode 100644 source/test/fixtures/expect-error/values-disabled-no-implicit-any/package.json diff --git a/source/lib/compiler.ts b/source/lib/compiler.ts index 0aea524a..12e5fcf4 100644 --- a/source/lib/compiler.ts +++ b/source/lib/compiler.ts @@ -27,7 +27,12 @@ const expectErrordiagnosticCodesToIgnore = new Set([ DiagnosticCode.NoOverloadMatches, DiagnosticCode.PropertyMissingInType1ButRequiredInType2, DiagnosticCode.TypeHasNoPropertiesInCommonWith, - DiagnosticCode.ThisContextOfTypeNotAssignableToMethodOfThisType + DiagnosticCode.ThisContextOfTypeNotAssignableToMethodOfThisType, + DiagnosticCode.ValueOfTypeNotCallable, + DiagnosticCode.ExpressionNotCallable, + DiagnosticCode.OnlyVoidFunctionIsNewCallable, + DiagnosticCode.ExpressionNotConstructable, + DiagnosticCode.NewExpressionTargetLackingConstructSignatureHasAnyType, ]); type IgnoreDiagnosticResult = 'preserve' | 'ignore' | Location; diff --git a/source/lib/interfaces.ts b/source/lib/interfaces.ts index d9064214..160cbf97 100644 --- a/source/lib/interfaces.ts +++ b/source/lib/interfaces.ts @@ -30,9 +30,14 @@ export enum DiagnosticCode { CannotAssignToReadOnlyProperty = 2540, ExpectedArgumentsButGotOther = 2554, TypeHasNoPropertiesInCommonWith = 2559, - NoOverloadMatches = 2769, - PropertyMissingInType1ButRequiredInType2 = 2741, + ValueOfTypeNotCallable = 2348, + ExpressionNotCallable = 2349, + OnlyVoidFunctionIsNewCallable = 2350, + ExpressionNotConstructable = 2351, ThisContextOfTypeNotAssignableToMethodOfThisType = 2684, + PropertyMissingInType1ButRequiredInType2 = 2741, + NoOverloadMatches = 2769, + NewExpressionTargetLackingConstructSignatureHasAnyType = 7009, } export interface Diagnostic { diff --git a/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.d.ts b/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.d.ts new file mode 100644 index 00000000..1770c00b --- /dev/null +++ b/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.d.ts @@ -0,0 +1 @@ +export function hasProperty(property: {name: string}): boolean; diff --git a/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.js b/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.js new file mode 100644 index 00000000..f17717f5 --- /dev/null +++ b/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.js @@ -0,0 +1,3 @@ +module.exports.default = (foo, bar) => { + return foo + bar; +}; diff --git a/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.test-d.ts b/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.test-d.ts new file mode 100644 index 00000000..cf25e541 --- /dev/null +++ b/source/test/fixtures/expect-error/values-disabled-no-implicit-any/index.test-d.ts @@ -0,0 +1,5 @@ +import {expectError} from '../../../..'; +import {hasProperty} from '.'; + +// Only a void function can be called with the 'new' keyword. +expectError(new hasProperty({name: 'foo'})); diff --git a/source/test/fixtures/expect-error/values-disabled-no-implicit-any/package.json b/source/test/fixtures/expect-error/values-disabled-no-implicit-any/package.json new file mode 100644 index 00000000..34bf4263 --- /dev/null +++ b/source/test/fixtures/expect-error/values-disabled-no-implicit-any/package.json @@ -0,0 +1,8 @@ +{ + "name": "foo", + "tsd": { + "compilerOptions": { + "noImplicitAny": false + } + } +} diff --git a/source/test/fixtures/expect-error/values/index.d.ts b/source/test/fixtures/expect-error/values/index.d.ts index 3b8e73e2..938d95fe 100644 --- a/source/test/fixtures/expect-error/values/index.d.ts +++ b/source/test/fixtures/expect-error/values/index.d.ts @@ -14,3 +14,5 @@ export type HasKey = {[P in K]?: V}; export function getFoo>(obj: T): T['foo']; export interface Options {} + +export class MyClass {} diff --git a/source/test/fixtures/expect-error/values/index.test-d.ts b/source/test/fixtures/expect-error/values/index.test-d.ts index 8978ae3e..16d6ee62 100644 --- a/source/test/fixtures/expect-error/values/index.test-d.ts +++ b/source/test/fixtures/expect-error/values/index.test-d.ts @@ -1,5 +1,5 @@ import {expectError} from '../../../..'; -import {default as one, foo, getFoo, HasKey, hasProperty, Options} from '.'; +import {default as one, foo, getFoo, HasKey, hasProperty, MyClass, Options} from '.'; expectError(1); expectError('fo'); @@ -22,3 +22,12 @@ expectError(one(1, 2, 3)); expectError({} as Options); expectError(getFoo({bar: 1} as HasKey<'bar'>)); + +const bar = 1; +expectError(bar()); +expectError(new bar()); + +expectError(MyClass()); + +// 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type. +expectError(new hasProperty({name: 'foo'})); diff --git a/source/test/test.ts b/source/test/test.ts index efec9c23..7a837805 100644 --- a/source/test/test.ts +++ b/source/test/test.ts @@ -222,6 +222,12 @@ test('expectError for values', async t => { ]); }); +test('expectError for values (noImplicitAny disabled)', async t => { + const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/expect-error/values-disabled-no-implicit-any')}); + + verify(t, diagnostics, []); +}); + test('missing import', async t => { const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/missing-import')});