Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -8053,7 +8053,6 @@ func (c *Checker) checkCallExpression(node *ast.Node, checkMode CheckMode) *Type
if !ast.IsDottedName(node.Expression()) {
c.error(node.Expression(), diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name)
} else if c.getEffectsSignature(node) == nil {
c.error(node.Expression(), diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation)
diagnostic := c.error(node.Expression(), diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation)
c.getTypeOfDottedName(node.Expression(), diagnostic)
}
Expand Down
12 changes: 11 additions & 1 deletion internal/checker/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -2160,7 +2160,17 @@ func (c *Checker) getExplicitTypeOfSymbol(symbol *ast.Symbol, diagnostic *ast.Di
}

func (c *Checker) isDeclarationWithExplicitTypeAnnotation(node *ast.Node) bool {
return (ast.IsVariableDeclaration(node) || ast.IsPropertyDeclaration(node) || ast.IsPropertySignatureDeclaration(node) || ast.IsParameter(node)) && node.Type() != nil
return (ast.IsVariableDeclaration(node) || ast.IsPropertyDeclaration(node) || ast.IsPropertySignatureDeclaration(node) || ast.IsParameter(node)) && node.Type() != nil ||
c.isExpandoPropertyFunctionWithReturnTypeAnnotation(node)
}

func (c *Checker) isExpandoPropertyFunctionWithReturnTypeAnnotation(node *ast.Node) bool {
if ast.IsBinaryExpression(node) {
if expr := node.AsBinaryExpression().Right; ast.IsFunctionLike(expr) && expr.Type() != nil {
return true
}
}
return false
}

func (c *Checker) hasTypePredicateOrNeverReturnType(sig *Signature) bool {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//// [tests/cases/compiler/expandoFunctionAsAssertion.ts] ////

=== expandoFunctionAsAssertion.ts ===
function example() {}
>example : Symbol(example, Decl(expandoFunctionAsAssertion.ts, 0, 0))

example.isFoo = function isFoo(value: string): asserts value is 'foo' {
>example.isFoo : Symbol(example.isFoo, Decl(expandoFunctionAsAssertion.ts, 0, 21))
>example : Symbol(example, Decl(expandoFunctionAsAssertion.ts, 0, 0))
>isFoo : Symbol(example.isFoo, Decl(expandoFunctionAsAssertion.ts, 0, 21))
>isFoo : Symbol(isFoo, Decl(expandoFunctionAsAssertion.ts, 2, 15))
>value : Symbol(value, Decl(expandoFunctionAsAssertion.ts, 2, 31))
>value : Symbol(value, Decl(expandoFunctionAsAssertion.ts, 2, 31))

if (value !== 'foo') {
>value : Symbol(value, Decl(expandoFunctionAsAssertion.ts, 2, 31))

throw new Error('Not foo');
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
}
};

example.isFoo('test');
>example.isFoo : Symbol(example.isFoo, Decl(expandoFunctionAsAssertion.ts, 0, 21))
>example : Symbol(example, Decl(expandoFunctionAsAssertion.ts, 0, 0))
>isFoo : Symbol(example.isFoo, Decl(expandoFunctionAsAssertion.ts, 0, 21))

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//// [tests/cases/compiler/expandoFunctionAsAssertion.ts] ////

=== expandoFunctionAsAssertion.ts ===
function example() {}
>example : { (): void; isFoo: (value: string) => asserts value is "foo"; }

example.isFoo = function isFoo(value: string): asserts value is 'foo' {
>example.isFoo = function isFoo(value: string): asserts value is 'foo' { if (value !== 'foo') { throw new Error('Not foo'); }} : (value: string) => asserts value is "foo"
>example.isFoo : (value: string) => asserts value is "foo"
>example : { (): void; isFoo: (value: string) => asserts value is "foo"; }
>isFoo : (value: string) => asserts value is "foo"
>function isFoo(value: string): asserts value is 'foo' { if (value !== 'foo') { throw new Error('Not foo'); }} : (value: string) => asserts value is "foo"
>isFoo : (value: string) => asserts value is "foo"
>value : string

if (value !== 'foo') {
>value !== 'foo' : boolean
>value : string
>'foo' : "foo"

throw new Error('Not foo');
>new Error('Not foo') : Error
>Error : ErrorConstructor
>'Not foo' : "Not foo"
}
};

example.isFoo('test');
>example.isFoo('test') : void
>example.isFoo : (value: string) => asserts value is "foo"
>example : { (): void; isFoo: (value: string) => asserts value is "foo"; }
>isFoo : (value: string) => asserts value is "foo"
>'test' : "test"

12 changes: 12 additions & 0 deletions testdata/tests/cases/compiler/expandoFunctionAsAssertion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @strict: true
// @noEmit: true

function example() {}

example.isFoo = function isFoo(value: string): asserts value is 'foo' {
if (value !== 'foo') {
throw new Error('Not foo');
}
};

example.isFoo('test');