Skip to content

Commit b8983f4

Browse files
authored
Permit expando property function with return type annotation as assertion (#1787)
1 parent 6277711 commit b8983f4

File tree

5 files changed

+84
-2
lines changed

5 files changed

+84
-2
lines changed

internal/checker/checker.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8053,7 +8053,6 @@ func (c *Checker) checkCallExpression(node *ast.Node, checkMode CheckMode) *Type
80538053
if !ast.IsDottedName(node.Expression()) {
80548054
c.error(node.Expression(), diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name)
80558055
} else if c.getEffectsSignature(node) == nil {
8056-
c.error(node.Expression(), diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation)
80578056
diagnostic := c.error(node.Expression(), diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation)
80588057
c.getTypeOfDottedName(node.Expression(), diagnostic)
80598058
}

internal/checker/flow.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2160,7 +2160,17 @@ func (c *Checker) getExplicitTypeOfSymbol(symbol *ast.Symbol, diagnostic *ast.Di
21602160
}
21612161

21622162
func (c *Checker) isDeclarationWithExplicitTypeAnnotation(node *ast.Node) bool {
2163-
return (ast.IsVariableDeclaration(node) || ast.IsPropertyDeclaration(node) || ast.IsPropertySignatureDeclaration(node) || ast.IsParameter(node)) && node.Type() != nil
2163+
return (ast.IsVariableDeclaration(node) || ast.IsPropertyDeclaration(node) || ast.IsPropertySignatureDeclaration(node) || ast.IsParameter(node)) && node.Type() != nil ||
2164+
c.isExpandoPropertyFunctionWithReturnTypeAnnotation(node)
2165+
}
2166+
2167+
func (c *Checker) isExpandoPropertyFunctionWithReturnTypeAnnotation(node *ast.Node) bool {
2168+
if ast.IsBinaryExpression(node) {
2169+
if expr := node.AsBinaryExpression().Right; ast.IsFunctionLike(expr) && expr.Type() != nil {
2170+
return true
2171+
}
2172+
}
2173+
return false
21642174
}
21652175

21662176
func (c *Checker) hasTypePredicateOrNeverReturnType(sig *Signature) bool {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [tests/cases/compiler/expandoFunctionAsAssertion.ts] ////
2+
3+
=== expandoFunctionAsAssertion.ts ===
4+
function example() {}
5+
>example : Symbol(example, Decl(expandoFunctionAsAssertion.ts, 0, 0))
6+
7+
example.isFoo = function isFoo(value: string): asserts value is 'foo' {
8+
>example.isFoo : Symbol(example.isFoo, Decl(expandoFunctionAsAssertion.ts, 0, 21))
9+
>example : Symbol(example, Decl(expandoFunctionAsAssertion.ts, 0, 0))
10+
>isFoo : Symbol(example.isFoo, Decl(expandoFunctionAsAssertion.ts, 0, 21))
11+
>isFoo : Symbol(isFoo, Decl(expandoFunctionAsAssertion.ts, 2, 15))
12+
>value : Symbol(value, Decl(expandoFunctionAsAssertion.ts, 2, 31))
13+
>value : Symbol(value, Decl(expandoFunctionAsAssertion.ts, 2, 31))
14+
15+
if (value !== 'foo') {
16+
>value : Symbol(value, Decl(expandoFunctionAsAssertion.ts, 2, 31))
17+
18+
throw new Error('Not foo');
19+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
20+
}
21+
};
22+
23+
example.isFoo('test');
24+
>example.isFoo : Symbol(example.isFoo, Decl(expandoFunctionAsAssertion.ts, 0, 21))
25+
>example : Symbol(example, Decl(expandoFunctionAsAssertion.ts, 0, 0))
26+
>isFoo : Symbol(example.isFoo, Decl(expandoFunctionAsAssertion.ts, 0, 21))
27+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/compiler/expandoFunctionAsAssertion.ts] ////
2+
3+
=== expandoFunctionAsAssertion.ts ===
4+
function example() {}
5+
>example : { (): void; isFoo: (value: string) => asserts value is "foo"; }
6+
7+
example.isFoo = function isFoo(value: string): asserts value is 'foo' {
8+
>example.isFoo = function isFoo(value: string): asserts value is 'foo' { if (value !== 'foo') { throw new Error('Not foo'); }} : (value: string) => asserts value is "foo"
9+
>example.isFoo : (value: string) => asserts value is "foo"
10+
>example : { (): void; isFoo: (value: string) => asserts value is "foo"; }
11+
>isFoo : (value: string) => asserts value is "foo"
12+
>function isFoo(value: string): asserts value is 'foo' { if (value !== 'foo') { throw new Error('Not foo'); }} : (value: string) => asserts value is "foo"
13+
>isFoo : (value: string) => asserts value is "foo"
14+
>value : string
15+
16+
if (value !== 'foo') {
17+
>value !== 'foo' : boolean
18+
>value : string
19+
>'foo' : "foo"
20+
21+
throw new Error('Not foo');
22+
>new Error('Not foo') : Error
23+
>Error : ErrorConstructor
24+
>'Not foo' : "Not foo"
25+
}
26+
};
27+
28+
example.isFoo('test');
29+
>example.isFoo('test') : void
30+
>example.isFoo : (value: string) => asserts value is "foo"
31+
>example : { (): void; isFoo: (value: string) => asserts value is "foo"; }
32+
>isFoo : (value: string) => asserts value is "foo"
33+
>'test' : "test"
34+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
function example() {}
5+
6+
example.isFoo = function isFoo(value: string): asserts value is 'foo' {
7+
if (value !== 'foo') {
8+
throw new Error('Not foo');
9+
}
10+
};
11+
12+
example.isFoo('test');

0 commit comments

Comments
 (0)