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): new ruleno-unsafe-type-assertion#10051

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
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
28 commits
Select commitHold shift + click to select a range
8f38cec
initial implementation
ronamiSep 24, 2024
037978c
tests
ronamiSep 24, 2024
a50625b
docs
ronamiSep 24, 2024
15ce7f8
more tests
ronamiSep 24, 2024
7c44606
use checker.typeToString() over getTypeName()
ronamiSep 24, 2024
cc4ea8b
use link
ronamiSep 25, 2024
e31cf39
oops
ronamiSep 25, 2024
8a8965f
add tests
ronamiSep 28, 2024
5bbe0c9
Merge branch 'main' into no-unsafe-type-assertion
ronamiSep 28, 2024
f0c429e
Merge branch 'main' into no-unsafe-type-assertion
ronamiOct 11, 2024
08577a8
remove unnecessary typescript 5.4 warning
ronamiOct 11, 2024
2ab1c87
adjust format to new rules
ronamiOct 11, 2024
8f29e89
Merge branch 'main' into no-unsafe-type-assertion
ronamiOct 15, 2024
a5dbd5b
update error message to be more concise
ronamiOct 11, 2024
ff73c4d
match implementation to be inline with no-unsafe-* rules
ronamiOct 15, 2024
913529f
rework tests
ronamiOct 15, 2024
88d15de
refactor
ronamiOct 15, 2024
c4f7ce7
update snapshots
ronamiOct 15, 2024
c34f7c1
fix error message showing original type instead of asserted type
ronamiOct 25, 2024
e93cca5
update snapshots
ronamiOct 25, 2024
1d32280
add a warning for object stubbing on test files
ronamiOct 25, 2024
d4c5236
fix linting
ronamiOct 25, 2024
03ae3bc
adjust test to lint fixes
ronamiOct 25, 2024
9980c9e
simplify type comparison
ronamiNov 10, 2024
8b0912f
rework code-comments and rename variables
ronamiNov 10, 2024
07ae890
rework the opening paragraph to make it more beginner-friendly
ronamiNov 10, 2024
5d8c521
Update packages/eslint-plugin/docs/rules/no-unsafe-type-assertion.mdx
ronamiNov 11, 2024
033fd0b
fix: narrow/widen in description
JoshuaKGoldbergNov 14, 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
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
---
description: 'Disallow type assertions that narrow a type.'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

> 🛑 This file is source code, not the primary documentation location! 🛑
>
> See **https://typescript-eslint.io/rules/no-unsafe-type-assertion** for documentation.

Type assertions are a way to tell TypeScript what the type of a value is. This can be useful but also unsafe if you use type assertions to narrow down a type.

This rule forbids using type assertions to narrow a type, as this bypasses TypeScript's type-checking. Type assertions that broaden a type are safe because TypeScript essentially knows _less_ about a type.

Instead of using type assertions to narrow a type, it's better to rely on type guards, which help avoid potential runtime errors caused by unsafe type assertions.

## Examples

<Tabs>
<TabItem value="❌ Incorrect">

```ts
function f() {
return Math.random() < 0.5 ? 42 : 'oops';
}

const z = f() as number;

const items = [1, '2', 3, '4'];

const number = items[0] as number;
```

</TabItem>
<TabItem value="✅ Correct">

```ts
function f() {
return Math.random() < 0.5 ? 42 : 'oops';
}

const z = f() as number | string | boolean;

const items = [1, '2', 3, '4'];

const number = items[0] as number | string | undefined;
```

</TabItem>
</Tabs>

## When Not To Use It

If your codebase has many unsafe type assertions, then it may be difficult to enable this rule.
It may be easier to skip the `no-unsafe-*` rules pending increasing type safety in unsafe areas of your project.
You might consider using [ESLint disable comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) for those specific situations instead of completely disabling this rule.

If your project frequently stubs objects in test files, the rule may trigger a lot of reports. Consider disabling the rule for such files to reduce frequent warnings.

## Further Reading

- More on TypeScript's [type assertions](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions)
1 change: 1 addition & 0 deletionspackages/eslint-plugin/src/configs/all.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -106,6 +106,7 @@ export = {
'@typescript-eslint/no-unsafe-function-type': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-unsafe-type-assertion': 'error',
'@typescript-eslint/no-unsafe-unary-minus': 'error',
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': 'error',
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,6 +40,7 @@ export = {
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unsafe-type-assertion': 'off',
'@typescript-eslint/no-unsafe-unary-minus': 'off',
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
'@typescript-eslint/only-throw-error': 'off',
Expand Down
2 changes: 2 additions & 0 deletionspackages/eslint-plugin/src/rules/index.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,6 +83,7 @@ import noUnsafeEnumComparison from './no-unsafe-enum-comparison';
import noUnsafeFunctionType from './no-unsafe-function-type';
import noUnsafeMemberAccess from './no-unsafe-member-access';
import noUnsafeReturn from './no-unsafe-return';
import noUnsafeTypeAssertion from './no-unsafe-type-assertion';
import noUnsafeUnaryMinus from './no-unsafe-unary-minus';
import noUnusedExpressions from './no-unused-expressions';
import noUnusedVars from './no-unused-vars';
Expand DownExpand Up@@ -213,6 +214,7 @@ const rules = {
'no-unsafe-function-type': noUnsafeFunctionType,
'no-unsafe-member-access': noUnsafeMemberAccess,
'no-unsafe-return': noUnsafeReturn,
'no-unsafe-type-assertion': noUnsafeTypeAssertion,
'no-unsafe-unary-minus': noUnsafeUnaryMinus,
'no-unused-expressions': noUnusedExpressions,
'no-unused-vars': noUnusedVars,
Expand Down
146 changes: 146 additions & 0 deletionspackages/eslint-plugin/src/rules/no-unsafe-type-assertion.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
import type { TSESTree } from '@typescript-eslint/utils';

import * as tsutils from 'ts-api-utils';
import * as ts from 'typescript';

import {
createRule,
getConstrainedTypeAtLocation,
getParserServices,
isTypeAnyType,
isTypeUnknownType,
isUnsafeAssignment,
} from '../util';

export default createRule({
name: 'no-unsafe-type-assertion',
meta: {
type: 'problem',
docs: {
description: 'Disallow type assertions that narrow a type',
requiresTypeChecking: true,
},
messages: {
unsafeOfAnyTypeAssertion:
'Unsafe cast from {{type}} detected: consider using type guards or a safer cast.',
unsafeToAnyTypeAssertion:
'Unsafe cast to {{type}} detected: consider using a more specific type to ensure safety.',
unsafeTypeAssertion:
"Unsafe type assertion: type '{{type}}' is more narrow than the original type.",
},
schema: [],
},
defaultOptions: [],
create(context) {
const services = getParserServices(context);
const checker = services.program.getTypeChecker();

function getAnyTypeName(type: ts.Type): string {
return tsutils.isIntrinsicErrorType(type) ? 'error typed' : '`any`';
}

function isObjectLiteralType(type: ts.Type): boolean {
return (
tsutils.isObjectType(type) &&
tsutils.isObjectFlagSet(type, ts.ObjectFlags.ObjectLiteral)
);
}

function checkExpression(
node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion,
): void {
const expressionType = getConstrainedTypeAtLocation(
services,
node.expression,
);
const assertedType = getConstrainedTypeAtLocation(
services,
node.typeAnnotation,
);

if (expressionType === assertedType) {
return;
}

// handle cases when casting unknown ==> any.
if (isTypeAnyType(assertedType) && isTypeUnknownType(expressionType)) {
context.report({
node,
messageId: 'unsafeToAnyTypeAssertion',
data: {
type: '`any`',
},
});

return;
}

const unsafeExpressionAny = isUnsafeAssignment(
expressionType,
assertedType,
checker,
node.expression,
);

if (unsafeExpressionAny) {
context.report({
node,
messageId: 'unsafeOfAnyTypeAssertion',
data: {
type: getAnyTypeName(unsafeExpressionAny.sender),
},
});

return;
}

const unsafeAssertedAny = isUnsafeAssignment(
assertedType,
expressionType,
checker,
node.typeAnnotation,
);

if (unsafeAssertedAny) {
context.report({
node,
messageId: 'unsafeToAnyTypeAssertion',
data: {
type: getAnyTypeName(unsafeAssertedAny.sender),
},
});

return;
}

// Use the widened type in case of an object literal so `isTypeAssignableTo()`
// won't fail on excess property check.
const nodeWidenedType = isObjectLiteralType(expressionType)
? checker.getWidenedType(expressionType)
: expressionType;

const isAssertionSafe = checker.isTypeAssignableTo(
nodeWidenedType,
assertedType,
);

if (!isAssertionSafe) {
context.report({
node,
messageId: 'unsafeTypeAssertion',
data: {
type: checker.typeToString(assertedType),
},
});
}
}

return {
'TSAsExpression, TSTypeAssertion'(
node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion,
): void {
checkExpression(node);
},
};
},
});
View file
Open in desktop

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

Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp