I have the following typescript type:
export type Milliseconds = number & { __type: 'milliseconds' };
and i want to prevent anyone using the division operator on it like so:
const foo = 1 as Milliseconds;
const bar = foo / 2;
i have come up with the following eslint rule
"no-restricted-syntax": [
"error",
{
"selector": "BinaryExpression[left.typeAnnotation.typeName.name='Milliseconds'][operator='/']",
"message": "Milliseconds cannot be divided directly, please use the msDivide()."
},
],
but the rule only works when casting to milliseconds right before dividing so that this shows the error:
const foo = 1;
const bar = foo as Milliseconds / 2;
but this doesn't:
const foo = 1 as Milliseconds;
const bar = foo / 2;
from playing around with:
https://typescript-eslint.io/play/#ts=5.0.4&sourceType=module&showAST=es
it seems that the problem is that the AST doesnt keep a representation of the typeAnnotation in the identifier for foo
how do i write a selector that takes left
and find's it's type based on it's name?
Selectors operate solely on the AST. In particular with the no-restricted-syntax
rule you can only have one single selector that matches one node and reports on it - it's an intentionally very simple solution.
You'll need to write a custom rule to do this check. For the specific case you've listed in your question - you could achieve this using scope analysis, however for the more general case you will need to make this a type-aware rule because scope analysis cannot act across function or module boundaries.
For example consider this code:
// fileA.ts
declare function getCurrentTimeMillis(): Milliseconds;
// fileB.ts
import { getCurrentTimeMillis } from './fileA';
const x = getCurrentTimeMillis();
const y = x / 2; // ❌ OOPS
This sort of check requires type information - you need to inspect the type of x
to determine that it is of type Milliseconds
.
So the general logic of your custom rule would be
/
operator.Milliseconds
, then report.You can read more about typescript-eslint rules and type-aware rules here: https://typescript-eslint.io/custom-rules