Skip to content

Commit f701f0a

Browse files
committed
remove native collection types
1 parent 0460584 commit f701f0a

File tree

3 files changed

+63
-22
lines changed

3 files changed

+63
-22
lines changed

validator/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ It is configured [in the specification directory](../specification/eslint.config
99
|---------------------------------------| - |
1010
| `single-key-dictionary-key-is-string` | `SingleKeyDictionary` keys must be strings. |
1111
| `dictionary-key-is-string` | `Dictionary` keys must be strings. |
12-
| `no-native-types` | `Typescript native types not allowed, use aliases. |
12+
| `no-native-types` | TypeScript native utility types (`Record`, `Partial`, etc.) and collection types (`Map`, `Set`, etc.) are not allowed. Use spec-defined aliases like `Dictionary` instead. |
1313
| `invalid-node-types` | The spec uses a subset of TypeScript, so some types, clauses and expressions are not allowed. |
1414

1515
## Usage

validator/rules/no-native-types.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,45 @@ import { ESLintUtils } from '@typescript-eslint/utils';
2020

2121
const createRule = ESLintUtils.RuleCreator(name => `https://example.com/rule/${name}`)
2222

23-
const TYPES_TO_AVOID = ['Record', 'Partial', 'Required', 'Pick', 'Omit'];
23+
const UTILITY_TYPES = ['Record', 'Partial', 'Required', 'Pick', 'Omit'];
24+
25+
const COLLECTION_TYPES = ['Map', 'Set', 'WeakMap', 'WeakSet'];
26+
27+
const TYPES_TO_AVOID = [...UTILITY_TYPES, ...COLLECTION_TYPES];
28+
29+
const TYPE_SUGGESTIONS = {
30+
'Record': 'Use Dictionary instead',
31+
'Map': 'Use Dictionary instead',
32+
'Set': 'Use an array type instead (e.g., string[])',
33+
'WeakMap': 'Use Dictionary instead',
34+
'WeakSet': 'Use an array type instead',
35+
};
2436

2537
export default createRule({
2638
name: 'no-native-types',
2739
create(context) {
2840
return {
2941
TSTypeReference(node) {
30-
if (TYPES_TO_AVOID.includes(node.typeName.name)) {
31-
context.report({ node, messageId: 'stringKey' })
42+
const typeName = node.typeName.name;
43+
if (TYPES_TO_AVOID.includes(typeName)) {
44+
context.report({
45+
node,
46+
messageId: 'noNativeType',
47+
data: {
48+
type: typeName,
49+
suggestion: TYPE_SUGGESTIONS[typeName] || 'Use spec-defined aliases instead'
50+
}
51+
})
3252
}
3353
},
3454
}
3555
},
3656
meta: {
3757
docs: {
38-
description: 'Typescript native types not allowed, use aliases',
58+
description: 'TypeScript native utility and collection types not allowed, use spec-defined aliases',
3959
},
4060
messages: {
41-
stringKey: "Typescript native types not allowed, use aliases"
61+
noNativeType: 'Native TypeScript type "{{type}}" is not allowed. {{suggestion}}.'
4262
},
4363
type: 'suggestion',
4464
},

validator/test/no-native-types.test.js

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* under the License.
1818
*/
1919
import { RuleTester } from '@typescript-eslint/rule-tester'
20-
import rule from '../rules/dictionary-key-is-string.js'
20+
import rule from '../rules/no-native-types.js'
2121

2222
const ruleTester = new RuleTester({
2323
languageOptions: {
@@ -32,32 +32,53 @@ const ruleTester = new RuleTester({
3232

3333
ruleTester.run('no-native-types', rule, {
3434
valid: [
35-
`type MyRecord = Record<string, object>`,
36-
`type MyPart = Partial<Record>`,
37-
`type MyReq = Required<string>`,
38-
`type MyPick Pick<integer,"something">`,
39-
`type MyOmit = Omit<Record, "something">`,
35+
`type MyDict = Dictionary<string, object>`,
36+
`type MyMapping = Dictionary<string, any>`,
37+
`type MyArray = string[]`,
38+
`type MyList = Array<integer>`,
39+
`type MyType = { field: string }`,
40+
`class MyClass { prop: integer }`,
4041
],
4142
invalid: [
4243
{
4344
code: `type MyRecord = Record<string, object>`,
44-
errors: [{ messageId: 'stringKey' }]
45+
errors: [{ messageId: 'noNativeType' }]
4546
},
4647
{
47-
code: `type MyPart = Partial<Record>`,
48-
errors: [{ messageId: 'stringKey' }]
48+
code: `type MyPart = Partial<SomeType>`,
49+
errors: [{ messageId: 'noNativeType' }]
4950
},
5051
{
51-
code: `type MyReq = Required<string>`,
52-
errors: [{ messageId: 'stringKey' }]
52+
code: `type MyReq = Required<SomeType>`,
53+
errors: [{ messageId: 'noNativeType' }]
5354
},
5455
{
55-
code: `type MyPick Pick<integer,"something">`,
56-
errors: [{ messageId: 'stringKey' }]
56+
code: `type MyPick = Pick<SomeType, "field">`,
57+
errors: [{ messageId: 'noNativeType' }]
5758
},
5859
{
59-
code: `type MyOmit = Omit<Record, "something">`,
60-
errors: [{ messageId: 'stringKey' }]
61-
}
60+
code: `type MyOmit = Omit<SomeType, "field">`,
61+
errors: [{ messageId: 'noNativeType' }]
62+
},
63+
{
64+
code: `type MyMap = Map<string, object>`,
65+
errors: [{ messageId: 'noNativeType' }]
66+
},
67+
{
68+
code: `type MySet = Set<string>`,
69+
errors: [{ messageId: 'noNativeType' }]
70+
},
71+
{
72+
code: `type MyWeakMap = WeakMap<object, string>`,
73+
errors: [{ messageId: 'noNativeType' }]
74+
},
75+
{
76+
code: `type MyWeakSet = WeakSet<object>`,
77+
errors: [{ messageId: 'noNativeType' }]
78+
},
79+
{
80+
code: `class MyClass { items: Map<string, number> }`,
81+
errors: [{ messageId: 'noNativeType' }]
82+
},
6283
],
6384
})

0 commit comments

Comments
 (0)