Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
2 changes: 1 addition & 1 deletion validator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ It is configured [in the specification directory](../specification/eslint.config
|---------------------------------------| - |
| `single-key-dictionary-key-is-string` | `SingleKeyDictionary` keys must be strings. |
| `dictionary-key-is-string` | `Dictionary` keys must be strings. |
| `no-native-types` | `Typescript native types not allowed, use aliases. |
| `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. |
| `invalid-node-types` | The spec uses a subset of TypeScript, so some types, clauses and expressions are not allowed. |

## Usage
Expand Down
30 changes: 25 additions & 5 deletions validator/rules/no-native-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,45 @@ import { ESLintUtils } from '@typescript-eslint/utils';

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

const TYPES_TO_AVOID = ['Record', 'Partial', 'Required', 'Pick', 'Omit'];
const UTILITY_TYPES = ['Record', 'Partial', 'Required', 'Pick', 'Omit'];

const COLLECTION_TYPES = ['Map', 'Set', 'WeakMap', 'WeakSet'];
Copy link
Member

Choose a reason for hiding this comment

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

Can we please add Array to the list? It could also be a follow-up, as it generates 106 errors.

Copy link
Member Author

Choose a reason for hiding this comment

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

I will do this in a follow up pr


const TYPES_TO_AVOID = [...UTILITY_TYPES, ...COLLECTION_TYPES];

const TYPE_SUGGESTIONS = {
'Record': 'Use Dictionary instead',
'Map': 'Use Dictionary instead',
'Set': 'Use an array type instead (e.g., string[])',
'WeakMap': 'Use Dictionary instead',
'WeakSet': 'Use an array type instead',
};
Copy link
Member

Choose a reason for hiding this comment

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

When trying to add Array to the list, I added it to TYPE_SUGGESTIONS and realized it had no effect. Can we please stop using TYPES_TO_AVOID and TYPE_SUGGESTIONS and only rely on TYPE_SUGGESTIONS? Perhaps that will enable us to provide more helpful suggestions than "Use spec-defined aliases instead". (There's no equivalent to Omit or Pick, as far as I know.)


export default createRule({
name: 'no-native-types',
create(context) {
return {
TSTypeReference(node) {
if (TYPES_TO_AVOID.includes(node.typeName.name)) {
context.report({ node, messageId: 'stringKey' })
const typeName = node.typeName.name;
if (TYPES_TO_AVOID.includes(typeName)) {
context.report({
node,
messageId: 'noNativeType',
data: {
type: typeName,
suggestion: TYPE_SUGGESTIONS[typeName] || 'Use spec-defined aliases instead'
}
})
}
},
}
},
meta: {
docs: {
description: 'Typescript native types not allowed, use aliases',
description: 'TypeScript native utility and collection types not allowed, use spec-defined aliases',
},
messages: {
stringKey: "Typescript native types not allowed, use aliases"
noNativeType: 'Native TypeScript type "{{type}}" is not allowed. {{suggestion}}.'
},
type: 'suggestion',
},
Expand Down
53 changes: 37 additions & 16 deletions validator/test/no-native-types.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule from '../rules/dictionary-key-is-string.js'
import rule from '../rules/no-native-types.js'

const ruleTester = new RuleTester({
languageOptions: {
Expand All @@ -32,32 +32,53 @@ const ruleTester = new RuleTester({

ruleTester.run('no-native-types', rule, {
valid: [
`type MyRecord = Record<string, object>`,
`type MyPart = Partial<Record>`,
`type MyReq = Required<string>`,
`type MyPick Pick<integer,"something">`,
`type MyOmit = Omit<Record, "something">`,
`type MyDict = Dictionary<string, object>`,
Copy link
Member Author

Choose a reason for hiding this comment

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

The original test file had a bug...it included native types like Record, Partial, etc. in BOTH the valid and invalid arrays. This was contradictory and causing test failures.

I corrected the tests to properly reflect the rule's intent:

  • valid: Now uses spec-defined aliases (Dictionary) and allowed types (arrays, custom classes)
  • invalid: Contains native utility types (Record, Partial, etc.) and collection types (Map, Set, etc.)

also added test coverage for the new collection types (Map, Set, WeakMap, WeakSet).

`type MyMapping = Dictionary<string, any>`,
`type MyArray = string[]`,
`type MyList = Array<integer>`,
`type MyType = { field: string }`,
`class MyClass { prop: integer }`,
],
invalid: [
{
code: `type MyRecord = Record<string, object>`,
errors: [{ messageId: 'stringKey' }]
errors: [{ messageId: 'noNativeType' }]
},
{
code: `type MyPart = Partial<Record>`,
errors: [{ messageId: 'stringKey' }]
code: `type MyPart = Partial<SomeType>`,
errors: [{ messageId: 'noNativeType' }]
},
{
code: `type MyReq = Required<string>`,
errors: [{ messageId: 'stringKey' }]
code: `type MyReq = Required<SomeType>`,
errors: [{ messageId: 'noNativeType' }]
},
{
code: `type MyPick Pick<integer,"something">`,
errors: [{ messageId: 'stringKey' }]
code: `type MyPick = Pick<SomeType, "field">`,
errors: [{ messageId: 'noNativeType' }]
},
{
code: `type MyOmit = Omit<Record, "something">`,
errors: [{ messageId: 'stringKey' }]
}
code: `type MyOmit = Omit<SomeType, "field">`,
errors: [{ messageId: 'noNativeType' }]
},
{
code: `type MyMap = Map<string, object>`,
errors: [{ messageId: 'noNativeType' }]
},
{
code: `type MySet = Set<string>`,
errors: [{ messageId: 'noNativeType' }]
},
{
code: `type MyWeakMap = WeakMap<object, string>`,
errors: [{ messageId: 'noNativeType' }]
},
{
code: `type MyWeakSet = WeakSet<object>`,
errors: [{ messageId: 'noNativeType' }]
},
{
code: `class MyClass { items: Map<string, number> }`,
errors: [{ messageId: 'noNativeType' }]
},
],
})
Loading