Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(eslint-plugin): [no-unsafe-return] check promise any#8693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
JoshuaKGoldberg merged 22 commits intotypescript-eslint:mainfromyeonjuan:fix-8674
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
22 commits
Select commitHold shift + click to select a range
c48ff42
feat(eslint-plugin): [no-unsafe-return] check promise any
yeonjuanMar 17, 2024
2cf6004
add testcases
yeonjuanMar 17, 2024
7edaed9
Merge branch 'main' into fix-8674
yeonjuanApr 30, 2024
e84d6ab
apply reviews
yeonjuanApr 30, 2024
52c6715
Merge branch 'main' into fix-8674
yeonjuanMay 2, 2024
f24b746
fix lint errors
yeonjuanMay 2, 2024
014cd48
refactor
yeonjuanMay 2, 2024
6390a95
add type
yeonjuanMay 3, 2024
25daa68
improve messages
yeonjuanJun 12, 2024
979bd72
update comment
yeonjuanJun 12, 2024
4277c70
apply review
yeonjuanJun 12, 2024
3fb74b9
Merge branch 'main' into fix-8674
yeonjuanJul 9, 2024
c2d14e5
fix
yeonjuanJul 9, 2024
d2c0145
fix tests
yeonjuanJul 9, 2024
7f61819
update docs
yeonjuanJul 10, 2024
74e16c4
apply review
yeonjuanJul 15, 2024
8e5a19b
fix tests
yeonjuanJul 15, 2024
0d0a86a
change to use internal getAwaitedType
yeonjuanJul 17, 2024
fcca5ec
add todo comment
yeonjuanJul 18, 2024
2542bd5
Update packages/eslint-plugin/docs/rules/no-unsafe-return.mdx
yeonjuanJul 20, 2024
ccc2e97
apply reviews
yeonjuanJul 22, 2024
006d16c
Merge branch 'main' into fix-8674
yeonjuanJul 22, 2024
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
10 changes: 9 additions & 1 deletionpackages/eslint-plugin/docs/rules/no-unsafe-return.mdx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ Using `any` disables many type checking rules and is generally best used only as
Despite your best intentions, the `any` type can sometimes leak into your codebase.
Returning an an `any`-typed value from a function creates a potential type safety hole and source of bugs in your codebase.

This rule disallows returning `any` or `any[]` from a function.
This rule disallows returning `any` or `any[]` from a function and returning `Promise<any>` from an async function.

This rule also compares generic type argument types to ensure you don't return an unsafe `any` in a generic position to a function that's expecting a specific type.
For example, it will error if you return `Set<any>` from a function declared as returning `Set<string>`.
Expand DownExpand Up@@ -56,6 +56,10 @@ const foo10 = () => [] as any[];

const foo11 = (): string[] => [1, 2, 3] as any[];

async function foo13() {
return Promise.resolve({} as any);
}

// generic position examples
function assignability1(): Set<string> {
return new Set<any>([1]);
Expand All@@ -78,6 +82,10 @@ function foo2() {
const foo3 = () => [];
const foo4 = () => ['a'];

async function foo5() {
return Promise.resolve(1);
}

function assignability1(): Set<string> {
return new Set<string>(['foo']);
}
Expand Down
60 changes: 50 additions & 10 deletionspackages/eslint-plugin/src/rules/no-unsafe-return.ts
View file
Open in desktop
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

[docs] What do you think about mentioning this change in rule docs? IMO it would be nice to let people know that this rule also works with Promises

yeonjuan reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Original file line numberDiff line numberDiff line change
Expand Up@@ -6,11 +6,11 @@ import * as ts from 'typescript';
import {
AnyType,
createRule,
discriminateAnyType,
getConstrainedTypeAtLocation,
getContextualType,
getParserServices,
getThisExpression,
isAnyOrAnyArrayTypeDiscriminated,
isTypeAnyType,
isTypeFlagSet,
isTypeUnknownArrayType,
Expand All@@ -28,9 +28,9 @@ export default createRule({
requiresTypeChecking: true,
},
messages: {
unsafeReturn: 'Unsafe return ofan{{type}} typed value.',
unsafeReturn: 'Unsafe return ofa value of type{{type}}.',
unsafeReturnThis: [
'Unsafe return ofan`{{type}}` typed value. `this` is typed as `any`.',
'Unsafe return ofa value of type`{{type}}`. `this` is typed as `any`.',
'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.',
].join('\n'),
unsafeReturnAssignment:
Expand DownExpand Up@@ -78,7 +78,14 @@ export default createRule({
reportingNode: TSESTree.Node = returnNode,
): void {
const tsNode = services.esTreeNodeToTSNodeMap.get(returnNode);
const anyType = isAnyOrAnyArrayTypeDiscriminated(tsNode, checker);
const type = checker.getTypeAtLocation(tsNode);

const anyType = discriminateAnyType(
type,
checker,
services.program,
tsNode,
);
const functionNode = getParentFunctionNode(returnNode);
/* istanbul ignore if */ if (!functionNode) {
return;
Expand All@@ -100,27 +107,46 @@ export default createRule({
if (!functionType) {
functionType = services.getTypeAtLocation(functionNode);
}

const callSignatures = tsutils.getCallSignaturesOfType(functionType);
// If there is an explicit type annotation *and* that type matches the actual
// function return type, we shouldn't complain (it's intentional, even if unsafe)
if (functionTSNode.type) {
for (const signature of tsutils.getCallSignaturesOfType(functionType)) {
for (const signature of callSignatures) {
const signatureReturnType = signature.getReturnType();

if (
returnNodeType ===signature.getReturnType() ||
returnNodeType ===signatureReturnType ||
isTypeFlagSet(
signature.getReturnType(),
signatureReturnType,
ts.TypeFlags.Any | ts.TypeFlags.Unknown,
)
) {
return;
}
if (functionNode.async) {
const awaitedSignatureReturnType =
checker.getAwaitedType(signatureReturnType);

const awaitedReturnNodeType =
checker.getAwaitedType(returnNodeType);
if (
awaitedReturnNodeType === awaitedSignatureReturnType ||
(awaitedSignatureReturnType &&
isTypeFlagSet(
awaitedSignatureReturnType,
ts.TypeFlags.Any | ts.TypeFlags.Unknown,
))
) {
return;
}
}
}
}

if (anyType !== AnyType.Safe) {
// Allow cases when the declared return type of the function is either unknown or unknown[]
// and the function is returning any or any[].
for (const signature offunctionType.getCallSignatures()) {
for (const signature ofcallSignatures) {
const functionReturnType = signature.getReturnType();
if (
anyType === AnyType.Any &&
Expand All@@ -134,6 +160,18 @@ export default createRule({
) {
return;
}
const awaitedType = checker.getAwaitedType(functionReturnType);
if (
awaitedType &&
anyType === AnyType.PromiseAny &&
isTypeUnknownType(awaitedType)
) {
return;
}
}

if (anyType === AnyType.PromiseAny && !functionNode.async) {
return;
}

let messageId: 'unsafeReturn' | 'unsafeReturnThis' = 'unsafeReturn';
Expand DownExpand Up@@ -161,7 +199,9 @@ export default createRule({
? 'error'
: anyType === AnyType.Any
? '`any`'
: '`any[]`',
: anyType === AnyType.PromiseAny
? '`Promise<any>`'
: '`any[]`',
},
});
}
Expand Down
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

Loading

[8]ページ先頭

©2009-2025 Movatter.jp