Skip to content

Commit 2646db1

Browse files
committed
feat(strict-void-return): sync overload-safe callback typing with upstream
1 parent 26f876e commit 2646db1

File tree

3 files changed

+79
-19
lines changed

3 files changed

+79
-19
lines changed

internal/rule_tester/__snapshots__/strict-void-return.snap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,3 +1206,12 @@ Message: Value-returning function used in a context where a void function is exp
12061206
| ~~
12071207
6 | });
12081208
---
1209+
1210+
[TestStrictVoidReturnRule/invalid-109 - 1]
1211+
Diagnostic 1: nonVoidReturn (4:20 - 4:25)
1212+
Message: Value returned in a context where a void return is expected.
1213+
3 |
1214+
4 | f(undefined, () => 'test');
1215+
| ~~~~~~
1216+
5 |
1217+
---

internal/rules/strict_void_return/strict_void_return.go

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@ var StrictVoidReturnRule = rule.Rule{
6060
})
6161
}
6262

63+
isNullishOrAny := func(t *checker.Type) bool {
64+
return utils.IsTypeFlagSet(
65+
t,
66+
checker.TypeFlagsVoidLike|
67+
checker.TypeFlagsUndefined|
68+
checker.TypeFlagsNull|
69+
checker.TypeFlagsAny|
70+
checker.TypeFlagsNever,
71+
)
72+
}
73+
74+
isVoid := func(t *checker.Type) bool {
75+
return utils.IsTypeFlagSet(t, checker.TypeFlagsVoid)
76+
}
77+
6378
var reportIfNonVoidFunction func(funcNode *ast.Node)
6479
reportIfNonVoidFunction = func(funcNode *ast.Node) {
6580
actualType := checker.Checker_getApparentType(ctx.TypeChecker, ctx.TypeChecker.GetTypeAtLocation(funcNode))
@@ -145,10 +160,6 @@ var StrictVoidReturnRule = rule.Rule{
145160
continue
146161
}
147162

148-
if checkExpressionNode(argNode) {
149-
continue
150-
}
151-
152163
argExpectedReturnTypes := []*checker.Type{}
153164
for _, sig := range signatures {
154165
parameters := checker.Signature_parameters(sig)
@@ -163,24 +174,16 @@ var StrictVoidReturnRule = rule.Rule{
163174
}
164175
}
165176

166-
if len(argExpectedReturnTypes) == 0 {
177+
hasSingleSignature := len(signatures) == 1
178+
allSignaturesReturnVoid := utils.Every(argExpectedReturnTypes, func(returnType *checker.Type) bool {
179+
return isVoid(returnType) || isNullishOrAny(returnType) || utils.IsTypeParameter(returnType)
180+
})
181+
182+
if (hasSingleSignature || allSignaturesReturnVoid) && checkExpressionNode(argNode) {
167183
continue
168184
}
169185

170-
anyVoid := utils.Some(argExpectedReturnTypes, func(returnType *checker.Type) bool {
171-
return utils.IsTypeFlagSet(returnType, checker.TypeFlagsVoid)
172-
})
173-
allVoidLike := utils.Every(argExpectedReturnTypes, func(returnType *checker.Type) bool {
174-
return utils.IsTypeFlagSet(
175-
returnType,
176-
checker.TypeFlagsVoidLike|
177-
checker.TypeFlagsUndefined|
178-
checker.TypeFlagsNull|
179-
checker.TypeFlagsAny|
180-
checker.TypeFlagsNever,
181-
)
182-
})
183-
if anyVoid && allVoidLike {
186+
if utils.Some(argExpectedReturnTypes, isVoid) && utils.Every(argExpectedReturnTypes, isNullishOrAny) {
184187
reportIfNonVoidFunction(argNode)
185188
}
186189
}

internal/rules/strict_void_return/strict_void_return_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,27 @@ new Foo(() => false);
212212
Code: `
213213
declare function foo(cb: () => boolean): void;
214214
declare function foo(cb: () => void): void;
215+
foo(() => false);
216+
`,
217+
},
218+
{
219+
Code: `
220+
declare function foo(cb: () => void): void;
221+
declare function foo(cb: () => boolean): void;
215222
foo(() => false);
216223
`,
217224
},
218225
{
219226
Code: `
220227
declare function foo(cb: () => Promise<void>): void;
221228
declare function foo(cb: () => void): void;
229+
foo(async () => {});
230+
`,
231+
},
232+
{
233+
Code: `
234+
declare function foo(fn: () => void): void;
235+
declare function foo(fn: () => Promise<void>): void;
222236
foo(async () => {});
223237
`,
224238
},
@@ -917,6 +931,30 @@ foo((arg: number) => {
917931
function cb() {
918932
return true;
919933
}
934+
`,
935+
},
936+
{
937+
Code: `
938+
declare function f<T extends void>(arg: T, cb: () => T): void;
939+
declare function f<T extends string>(arg: T, cb: () => T): void;
940+
941+
f('test', () => 'test');
942+
f(undefined, () => {});
943+
`,
944+
},
945+
{
946+
Code: `
947+
interface HookFunction<T extends void | Hook = void> {
948+
(fn: () => void): T;
949+
(fn: () => Promise<void>): T;
950+
}
951+
952+
class Hook {}
953+
954+
declare var beforeEach: HookFunction<Hook>;
955+
956+
beforeEach(() => {});
957+
beforeEach(async () => {});
920958
`,
921959
},
922960
}
@@ -2316,6 +2354,16 @@ async function* cb() {
23162354
{MessageId: "nonVoidFunc", Line: 5},
23172355
},
23182356
},
2357+
{
2358+
Code: `
2359+
declare function f<T extends void>(arg: T, cb: () => T): void;
2360+
2361+
f(undefined, () => 'test');
2362+
`,
2363+
Errors: []rule_tester.InvalidTestCaseError{
2364+
{MessageId: "nonVoidReturn", Line: 4},
2365+
},
2366+
},
23192367
}
23202368

23212369
rule_tester.RunRuleTester(fixtures.GetRootDir(), "tsconfig.minimal.json", t, &StrictVoidReturnRule, validCases, invalidCases)

0 commit comments

Comments
 (0)