Inside a type, typeof name means "the type of the value called name". {Partial<typeof defaults>} reuses the shape of a settings object as the type of its overrides, so adding a setting to defaults updates the parameter type too. A wrong value type in the overrides is still TS2322, as the first example shows.
This is a type operator, not JavaScript's run-time typeof, which returns a string such as "object". The two share a keyword and nothing else.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| The type of a value | /** @param {Partial<typeof defaults>} overrides */ | (overrides: Partial<typeof defaults>) |
| The type of a function | /** @type {typeof formatPrice} */ | : typeof formatPrice |
Examples
const defaults = {
currency: "USD",
pageSize: 24,
showOutOfStock: false,
};
/**
* @param {Partial<typeof defaults>} overrides
* @returns {typeof defaults}
*/
export function settings(overrides) {
return { ...defaults, ...overrides };
}
settings({ pageSize: 48 });
settings({ pageSize: "48" });error TS2322: Type 'string' is not assignable to type 'number'.const defaults = {
currency: "USD",
pageSize: 24,
showOutOfStock: false,
};
export function settings(overrides: Partial<typeof defaults>): typeof defaults {
return { ...defaults, ...overrides };
}
settings({ pageSize: 48 });
settings({ pageSize: "48" });error TS2322: Type 'string' is not assignable to type 'number'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /**
* @param {number} amount
* @param {string} [currency]
*/
export function formatPrice(amount, currency = "USD") {
return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
}
/** @type {typeof formatPrice} */
export const formatEuro = (amount, currency = "EUR") => formatPrice(amount, currency);
formatEuro(19.5);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /** @typedef {{ currency: string }} Settings */
/** @type {typeof Settings} */error TS2693: 'Settings' only refers to a type, but is being used as a value here.
const settings = { currency: "USD" };
export { settings };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} It takes a value
typeof must be followed by a value. A @typedef name is a type, so {typeof Settings} is TS2693 ("'Settings' only refers to a type, but is being used as a value here"), as the third example shows. A class name works either way: {Cart} is the instance type, {typeof Cart} the class itself with its constructor and static members.
Value names without typeof in a .js file
In a .js file TypeScript also accepts a value's name in a JSDoc type and uses the value's type: {defaults} means the same as {typeof defaults}, and ReturnType<createCart> works without the typeof. A .ts file rejects both (TS2749). Writing typeof keeps the JSDoc valid TypeScript and makes the intent clear; the ReturnType page shows the difference side by side.
Gotchas
typeofcaptures the widened type of aletor a mutable object property (string, not"USD"). Use aconstassertion on the value to keep literal types.typeof import("./config.js")gives the type of a whole module.
Questions
How do I get the type of a variable in JSDoc?
Write typeof and the variable's name inside the braces: /** @type {typeof defaults} */.
Sources
- Typeof Type Operator · TypeScript handbook
- JSDoc Reference: import types and typeof · TypeScript handbook
Last reviewed 20 October 2026.