TypeScript error

TS2693: A type used where JavaScript needs a value

  • Error TS2693
  • Tested with TypeScript 5.9

error TS2693: 'Product' only refers to a type, but is being used as a value here. is reported when code that runs (an expression) uses a name that exists only for the checker. A @typedef declares a type and nothing at run time, so value instanceof Product has no Product to test against.

The same message shows up when TypeScript syntax is pasted into a .js file: new Set<string>() is read as the comparisons new Set < string > (), and string is a type, not a value. The parser also reports Expression expected. (TS1109) on the empty parentheses.

At a glance

CodeTS2693
Message'{0}' only refers to a type, but is being used as a value here.
TypeScript's categoryerror
Listed underUnknown names and members
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} is filled in by tsc for each error.

What it looks like

product.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: product.js(6,27): error TS2693: 'Product' only refers to a type, but is being used as a value here. product.js(10,28): error TS2693: 'string' only refers to a type, but is being used as a value here. product.js(10,36): error TS1109: Expression expected. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. product.js(6,27): error TS2693: 'Product' only refers to a type, but is being used as a value here. product.js(10,28): error TS2693: 'string' only refers to a type, but is being used as a value here. product.js(10,36): error TS1109: Expression expected. 7.0.2 : differs, see why TypeScript 7.0.2, run 21 October 2026: differs from 5.9.3. product.js(10,36): error TS1109: Expression expected. checked 21 October 2026
/** @typedef {{ sku: string, price: number }} Product */

/** @param {unknown} value */
export function isProduct(value) {
  return value instanceof Product;error TS2693: 'Product' only refers to a type, but is being used as a value here.
}

export const ids = new Set<string>();error TS2693: 'string' only refers to a type, but is being used as a value here.error TS1109: Expression expected.
Using a @typedef name where JavaScript needs a value.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

What causes it

  • A @typedef or @callback name, or a type imported with @import, is used with instanceof, new, or as a variable.
  • Type arguments in angle brackets are written in a .js file, where they are not syntax.

How to fix it

Check the shape with a type guard

To test whether a value is a Product, check its properties in a function whose @returns {value is Product} tells the checker what a true result means. If you need instanceof, make Product a class: a class is both a value and a type.

product.js TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/** @typedef {{ sku: string, price: number }} Product */

/**
 * @param {unknown} value
 * @returns {value is Product}
 */
export function isProduct(value) {
  return typeof value === "object" && value !== null && "sku" in value && "price" in value;
}

/** @type {Set<string>} */
export const ids = new Set();
A type guard for the check, and the type in a JSDoc tag.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Put type arguments in a JSDoc tag

Instead of new Set<string>(), annotate the variable: /** @type {Set<string>} */ const ids = new Set();. For a generic function call, annotate the result or cast the argument, as the generics page shows.

Under TypeScript 6.0 and 7.0

Every example on this page also runs under TypeScript 6.0.3 and 7.0.2 when this site is built. One of them reports something different from 5.9.3, the version the page describes; the ✗ on its badge links to its entry below.

A @typedef name used as a value is not reported

TypeScript 7.0 · JSDoc and JavaScript patterns 7.0 no longer reads

The pattern: value instanceof Product, where Product is a @typedef, and a type name in a value position (new Set<string>() in a .js file).

Why: 5.9 reports TS2693 ("only refers to a type, but is being used as a value"); TypeScript 7.0.2 reports neither, and keeps only the syntax error TS1109 for the type argument. The port's list of changes does not mention it. The code still fails when it runs. Source: CHANGES.md: changes between TypeScript 6 and the native port.

Using a @typedef name where JavaScript needs a value product.js

TypeScript 5.9.3
product.js(6,27): error TS2693: 'Product' only refers to a type, but is being used as a value here.
product.js(10,28): error TS2693: 'string' only refers to a type, but is being used as a value here.
product.js(10,36): error TS1109: Expression expected.
TypeScript 6.0.3same as 5.9.3

The same errors as 5.9.3.

TypeScript 7.0.2differs from 5.9.3
product.js(10,36): error TS1109: Expression expected.

What works in every version: Check the shape with a type guard, and give the Set its type with @type.

The example A type guard for the check, and the type in a JSDoc tag on this page shows it, with the same result under every version.

Gotchas

  • The reverse does not apply in a .js file: a value's name used as a type in JSDoc, such as @type {defaults}, is read as typeof defaults and not reported. Writing typeof is still clearer.
  • With an old lib, Promise and Symbol are reported with a variant of this message that suggests changing lib (TS2585); see TS2583.

Sources

Last reviewed 20 October 2026.