@@ -259,11 +259,13 @@ function arrayCondition(
259
259
)
260
260
}
261
261
262
- function objectTypeCondition ( varName : string ) : string {
263
- return ors (
264
- ands ( ne ( varName , 'null' ) , typeOf ( varName , 'object' ) ) ,
265
- typeOf ( varName , 'function' )
266
- )
262
+ function objectTypeCondition ( varName : string , callable : boolean ) : string {
263
+ return callable
264
+ ? typeOf ( varName , 'function' )
265
+ : ors (
266
+ ands ( ne ( varName , 'null' ) , typeOf ( varName , 'object' ) ) ,
267
+ typeOf ( varName , 'function' )
268
+ )
267
269
}
268
270
269
271
function objectCondition (
@@ -298,6 +300,27 @@ function objectCondition(
298
300
return null
299
301
}
300
302
303
+ const callable = type . getCallSignatures ( ) . length !== 0
304
+
305
+ if ( callable ) {
306
+ // emit warning
307
+ const suppressComment = 'ts-auto-guard-suppress function-type'
308
+ const commentsBefore = declaration . getLeadingCommentRanges ( )
309
+ const commentBefore = commentsBefore [ commentsBefore . length - 1 ]
310
+ if (
311
+ commentBefore === undefined ||
312
+ ! commentBefore . getText ( ) . includes ( suppressComment )
313
+ ) {
314
+ console . warn (
315
+ `
316
+ It seems that ${ varName } has a function type.
317
+ Note that it is impossible to check if a function has the correct signiture and return type at runtime.
318
+ To disable this warning, put comment "${ suppressComment } " before the declaration.
319
+ `
320
+ )
321
+ }
322
+ }
323
+
301
324
if ( type . isInterface ( ) ) {
302
325
if ( ! Node . isInterfaceDeclaration ( declaration ) ) {
303
326
throw new TypeError (
@@ -322,11 +345,14 @@ function objectCondition(
322
345
}
323
346
} )
324
347
if ( conditions . length === 0 ) {
325
- conditions . push ( objectTypeCondition ( varName ) )
348
+ conditions . push ( objectTypeCondition ( varName , callable ) )
326
349
}
327
- const properties = declaration
328
- . getProperties ( )
329
- . map ( p => ( { name : p . getName ( ) , type : p . getType ( ) } ) )
350
+
351
+ // getProperties does not include methods like `foo(): void`
352
+ const properties = [
353
+ ...declaration . getProperties ( ) ,
354
+ ...declaration . getMethods ( ) ,
355
+ ] . map ( p => ( { name : p . getName ( ) , type : p . getType ( ) } ) )
330
356
conditions . push (
331
357
...propertiesConditions (
332
358
varName ,
@@ -360,7 +386,7 @@ function objectCondition(
360
386
)
361
387
}
362
388
} else {
363
- conditions . push ( objectTypeCondition ( varName ) )
389
+ conditions . push ( objectTypeCondition ( varName , callable ) )
364
390
// Get object literal properties...
365
391
try {
366
392
const properties = type . getProperties ( )
0 commit comments