Add eslint rule for disallowing dangerous type assertions (#211669)

This adds a new (off by default) eslint rule that disables two specific types of dangerous type assertions:

```ts
<Type>{...};
{...} as Type;
```

These are bad because they can easily hide missing properties and strictness errors

Right now just adding this rule but will assign out fixes to owners in different areas of the code
This commit is contained in:
Matt Bierner 2024-04-30 11:27:22 -07:00 коммит произвёл GitHub
Родитель 431afbe459
Коммит 001929db91
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
5 изменённых файлов: 46 добавлений и 5 удалений

Просмотреть файл

@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/experimental-utils';
export = new class NoDangerousTypeAssertions implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
// Disable in tests for now
if (context.getFilename().includes('.test')) {
return {};
}
return {
// Disallow type assertions on object literals: <T>{ ... } or {} as T
['TSTypeAssertion > ObjectExpression, TSAsExpression > ObjectExpression']: (node: any) => {
const objectNode = node as TSESTree.Node;
const parent = objectNode.parent as TSESTree.TSTypeAssertion | TSESTree.TSAsExpression;
if (
// Allow `as const` assertions
(parent.typeAnnotation.type === 'TSTypeReference' && parent.typeAnnotation.typeName.type === 'Identifier' && parent.typeAnnotation.typeName.name === 'cost')
// For also now still allow `any` casts
|| (parent.typeAnnotation.type === 'TSAnyKeyword')
) {
return;
}
context.report({
node,
message: "Don't use type assertions for creating objects as this can hide type errors."
});
},
};
}
};

Просмотреть файл

@ -73,6 +73,7 @@
"local/code-parameter-properties-must-have-explicit-accessibility": "warn",
"local/code-no-nls-in-standalone-editor": "warn",
"local/code-no-potentially-unsafe-disposables": "warn",
"local/code-no-dangerous-type-assertions": "off",
"local/code-no-standalone-editor": "warn",
"local/code-no-unexternalized-strings": "warn",
"local/code-must-use-super-dispose": "warn",

Просмотреть файл

@ -246,7 +246,7 @@ export class FoldingRegions {
}
public toFoldRange(index: number): FoldRange {
return <FoldRange>{
return {
startLineNumber: this._startIndexes[index] & MAX_LINE_NUMBER,
endLineNumber: this._endIndexes[index] & MAX_LINE_NUMBER,
type: this._types ? this._types[index] : undefined,

Просмотреть файл

@ -370,7 +370,7 @@ export function registerChatCodeBlockActions() {
const editorService = accessor.get(IEditorService);
const chatService = accessor.get(IChatService);
editorService.openEditor(<IUntitledTextResourceEditorInput>{ contents: context.code, languageId: context.languageId, resource: undefined });
editorService.openEditor({ contents: context.code, languageId: context.languageId, resource: undefined } satisfies IUntitledTextResourceEditorInput);
if (isResponseVM(context.element)) {
chatService.notifyUserAction({

Просмотреть файл

@ -59,7 +59,7 @@ export class MarkersFilters extends Disposable {
set excludedFiles(filesExclude: boolean) {
if (this._excludedFiles.get() !== filesExclude) {
this._excludedFiles.set(filesExclude);
this._onDidChange.fire(<IMarkersFiltersChangeEvent>{ excludedFiles: true });
this._onDidChange.fire({ excludedFiles: true });
}
}
@ -70,7 +70,7 @@ export class MarkersFilters extends Disposable {
set activeFile(activeFile: boolean) {
if (this._activeFile.get() !== activeFile) {
this._activeFile.set(activeFile);
this._onDidChange.fire(<IMarkersFiltersChangeEvent>{ activeFile: true });
this._onDidChange.fire({ activeFile: true });
}
}
@ -81,7 +81,7 @@ export class MarkersFilters extends Disposable {
set showWarnings(showWarnings: boolean) {
if (this._showWarnings.get() !== showWarnings) {
this._showWarnings.set(showWarnings);
this._onDidChange.fire(<IMarkersFiltersChangeEvent>{ showWarnings: true });
this._onDidChange.fire({ showWarnings: true });
}
}