Skip to content

Commit 0017a0e

Browse files
armano2JamesHenry
authored andcommitted
[FEAT] [no-object-literal-type-assertion] Add rule (typescript-eslint#225)
1 parent e29e68f commit 0017a0e

File tree

4 files changed

+198
-0
lines changed

4 files changed

+198
-0
lines changed

packages/eslint-plugin-typescript/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ This guarantees 100% compatibility between the plugin and the parser.
6868
* [`typescript/no-misused-new`](./docs/rules/no-misused-new.md) — Enforce valid definition of `new` and `constructor`. (`no-misused-new` from TSLint)
6969
* [`typescript/no-namespace`](./docs/rules/no-namespace.md) — Disallow the use of custom TypeScript modules and namespaces
7070
* [`typescript/no-non-null-assertion`](./docs/rules/no-non-null-assertion.md) — Disallows non-null assertions using the `!` postfix operator (`no-non-null-assertion` from TSLint)
71+
* [`typescript/no-object-literal-type-assertion`](./docs/rules/no-object-literal-type-assertion.md) — Forbids an object literal to appear in a type assertion expression (`no-object-literal-type-assertion` from TSLint)
7172
* [`typescript/no-parameter-properties`](./docs/rules/no-parameter-properties.md) — Disallow the use of parameter properties in class constructors. (`no-parameter-properties` from TSLint)
7273
* [`typescript/no-triple-slash-reference`](./docs/rules/no-triple-slash-reference.md) — Disallow `/// <reference path="" />` comments (`no-reference` from TSLint)
7374
* [`typescript/no-type-alias`](./docs/rules/no-type-alias.md) — Disallow the use of type aliases (`interface-over-type-literal` from TSLint)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Forbids an object literal to appear in a type assertion expression (no-object-literal-type-assertion)
2+
3+
Always prefer `const x: T = { ... };` to `const x = { ... } as T;`. Casting to `any` and `unknown` is still allowed.
4+
5+
## Rule Details
6+
7+
Examples of **incorrect** code for this rule.
8+
9+
```ts
10+
const x = { ... } as T;
11+
```
12+
13+
Examples of **correct** code for this rule.
14+
15+
```ts
16+
const x: T = { ... };
17+
const y = { ... } as any;
18+
const z = { ... } as unknown;
19+
```
20+
21+
## Options
22+
```json
23+
{
24+
"typescript/no-object-literal-type-assertion": "error"
25+
}
26+
```
27+
28+
## Compatibility
29+
30+
* TSLint: [no-object-literal-type-assertion](https://palantir.github.io/tslint/rules/no-object-literal-type-assertion/)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* @fileoverview Forbids an object literal to appear in a type assertion expression
3+
* @author Armano <https://github.com/armano2>
4+
*/
5+
"use strict";
6+
7+
const util = require("../util");
8+
9+
//------------------------------------------------------------------------------
10+
// Rule Definition
11+
//------------------------------------------------------------------------------
12+
13+
module.exports = {
14+
meta: {
15+
docs: {
16+
description:
17+
"Forbids an object literal to appear in a type assertion expression",
18+
extraDescription: [
19+
util.tslintRule("no-object-literal-type-assertion"),
20+
],
21+
category: "TypeScript",
22+
url: util.metaDocsUrl("no-object-literal-type-assertions"),
23+
},
24+
messages: {
25+
unexpectedTypeAssertion:
26+
"Type assertion on object literals is forbidden, use a type annotation instead.",
27+
},
28+
schema: [],
29+
},
30+
create(context) {
31+
//----------------------------------------------------------------------
32+
// Public
33+
//----------------------------------------------------------------------
34+
35+
/**
36+
* Check whatever node should be reported
37+
* @param {ASTNode} node the node to be evaluated.
38+
* @returns {*} true or false
39+
*/
40+
function checkType(node) {
41+
if (
42+
node &&
43+
node.type === "TSTypeAnnotation" &&
44+
node.typeAnnotation
45+
) {
46+
switch (node.typeAnnotation.type) {
47+
case "TSAnyKeyword":
48+
case "TSUnknownKeyword":
49+
return false;
50+
default:
51+
break;
52+
}
53+
}
54+
return true;
55+
}
56+
57+
return {
58+
"TSTypeAssertionExpression, TSAsExpression"(node) {
59+
if (
60+
checkType(node.typeAnnotation) &&
61+
node.expression.type === "ObjectExpression"
62+
) {
63+
context.report({
64+
node,
65+
messageId: "unexpectedTypeAssertion",
66+
});
67+
}
68+
},
69+
};
70+
},
71+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/**
2+
* @fileoverview Forbids an object literal to appear in a type assertion expression
3+
* @author Armano <https://github.com/armano2>
4+
*/
5+
"use strict";
6+
7+
//------------------------------------------------------------------------------
8+
// Requirements
9+
//------------------------------------------------------------------------------
10+
11+
const rule = require("../../../lib/rules/no-object-literal-type-assertion"),
12+
RuleTester = require("eslint").RuleTester;
13+
14+
//------------------------------------------------------------------------------
15+
// Tests
16+
//------------------------------------------------------------------------------
17+
18+
const ruleTester = new RuleTester({
19+
parser: "typescript-eslint-parser",
20+
parserOptions: {
21+
ecmaVersion: 6,
22+
sourceType: "module",
23+
ecmaFeatures: {
24+
jsx: false,
25+
},
26+
},
27+
});
28+
29+
ruleTester.run("no-object-literal-type-assertion", rule, {
30+
valid: [
31+
{
32+
code: `<T> x;`,
33+
},
34+
{
35+
code: `x as T;`,
36+
},
37+
{
38+
code: `const foo = bar;`,
39+
},
40+
{
41+
code: `const foo: baz = bar;`,
42+
},
43+
{
44+
code: `const x: T = {};`,
45+
},
46+
{
47+
code: `const foo = { bar: { } };`,
48+
},
49+
// Allow cast to 'any'
50+
{
51+
code: `const foo = {} as any;`,
52+
},
53+
{
54+
code: `const foo = <any> {};`,
55+
},
56+
// Allow cast to 'unknown'
57+
{
58+
code: `const foo = {} as unknown;`,
59+
},
60+
{
61+
code: `const foo = <unknown> {};`,
62+
},
63+
],
64+
invalid: [
65+
{
66+
code: `<T> ({});`,
67+
errors: [
68+
{
69+
messageId: "unexpectedTypeAssertion",
70+
line: 1,
71+
column: 1,
72+
},
73+
],
74+
},
75+
{
76+
code: `({}) as T;`,
77+
errors: [
78+
{
79+
messageId: "unexpectedTypeAssertion",
80+
line: 1,
81+
column: 1,
82+
},
83+
],
84+
},
85+
{
86+
code: `const x = {} as T;`,
87+
errors: [
88+
{
89+
messageId: "unexpectedTypeAssertion",
90+
line: 1,
91+
column: 11,
92+
},
93+
],
94+
},
95+
],
96+
});

0 commit comments

Comments
 (0)