error TS2365: Operator '<' cannot be applied to types 'Date' and 'number'. is reported for <, >, <=, >= and + when the two operands are types the checker does not allow together. Relational operators accept two numbers, two bigints, two strings, any, or two values of related types (two Date objects compare without complaint); + needs numbers, or a string on one side.
In JavaScript code this usually means a Date compared with a timestamp, or text from a form compared with a number. Both work at run time through conversion, and both are easy to get subtly wrong, so the checker asks for the conversion to be written.
At a glance
| Code | TS2365 |
|---|---|
| Message | Operator '{0}' cannot be applied to types '{1}' and '{2}'. |
| TypeScript's category | error |
| Listed under | Types do not match |
| Turned on by | No option: every checked file reports it |
| In .js files | Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file |
The message is TypeScript's own text from its diagnostic messages file (Apache-2.0); {0}, {1} and {2} are filled in by tsc for each error.
What it looks like
/** @typedef {{ code: string, expiresAt: Date }} Coupon */
/** @param {Coupon} coupon */
export function isExpired(coupon) {
return coupon.expiresAt < Date.now();error TS2365: Operator '<' cannot be applied to types 'Date' and 'number'.
}
const field = document.querySelector("input");
export const bulk = field !== null && field.value > 10;error TS2365: Operator '>' cannot be applied to types 'string' and 'number'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} What causes it
- A
Dateis compared with a number (expiresAt < Date.now()). - A string is compared with a number (
field.value > 10). - Objects of unrelated types are compared, or two objects are added; JavaScript would convert them to strings or numbers first.
How to fix it
Compare numbers with numbers
Call getTime() on dates and convert text with Number(...) or valueAsNumber. Two Date objects can be compared with < and > without conversion (the checker allows it), but equality with === compares the objects, not the times, so getTime() is the habit worth keeping.
/** @typedef {{ code: string, expiresAt: Date }} Coupon */
/** @param {Coupon} coupon */
export function isExpired(coupon) {
return coupon.expiresAt.getTime() < Date.now();
}
const field = document.querySelector("input");
export const bulk = field !== null && field.valueAsNumber > 10;jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} When the operator is a pasted type argument
TypeScript code pasted into a .js file can produce TS2365 for no visible operator: first<string>(items) is read as two comparisons, first < string and > (items). The fix is JSDoc instead of type arguments; see TS2693.
Gotchas
- String comparison is allowed (
"apple" < "banana"), and compares by UTF-16 code units, so"10" < "9"is true. Convert before comparing numbers held as text. - For
-,*,/and%the messages are TS2362 and TS2363.
Sources
- Everyday Types · TypeScript handbook
- Less than (<) · MDN Web Docs
- diagnosticMessages.json (TypeScript 5.9.3) · TypeScript on GitHub
Last reviewed 20 October 2026.