Skip to content

Commit

Permalink
Allow expectError assertions to detect non-callable/non-constructab…
Browse files Browse the repository at this point in the history
…le values/expressions (#104)
  • Loading branch information
BendingBender committed May 27, 2021
1 parent 87f7109 commit 27ccc49
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 4 deletions.
7 changes: 6 additions & 1 deletion source/lib/compiler.ts
Expand Up @@ -27,7 +27,12 @@ const expectErrordiagnosticCodesToIgnore = new Set<DiagnosticCode>([
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;
Expand Down
9 changes: 7 additions & 2 deletions source/lib/interfaces.ts
Expand Up @@ -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 {
Expand Down
@@ -0,0 +1 @@
export function hasProperty(property: {name: string}): boolean;
@@ -0,0 +1,3 @@
module.exports.default = (foo, bar) => {
return foo + bar;
};
@@ -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'}));
@@ -0,0 +1,8 @@
{
"name": "foo",
"tsd": {
"compilerOptions": {
"noImplicitAny": false
}
}
}
2 changes: 2 additions & 0 deletions source/test/fixtures/expect-error/values/index.d.ts
Expand Up @@ -14,3 +14,5 @@ export type HasKey<K extends string, V = unknown> = {[P in K]?: V};
export function getFoo<T extends HasKey<'foo'>>(obj: T): T['foo'];

export interface Options<T> {}

export class MyClass {}
11 changes: 10 additions & 1 deletion 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<string>(1);
expectError<string>('fo');
Expand All @@ -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'}));
6 changes: 6 additions & 0 deletions source/test/test.ts
Expand Up @@ -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')});

Expand Down

0 comments on commit 27ccc49

Please sign in to comment.