Order["status"] is the type of the status property of Order. It lets a function take exactly what a property holds without repeating its definition, so the two stay in step when Order changes.
Indexing with number gives the element type of an array: Order["lines"][number] is the type of one line. Combined with a const assertion, (typeof SIZES)[number] turns an array of values into a union type.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| One property's type | /** @typedef {Order["status"]} OrderStatus */ | type OrderStatus = Order["status"]; |
| An array's element type | /** @typedef {Order["lines"][number]} OrderLine */ | type OrderLine = Order["lines"][number]; |
| Elements of a const array | /** @typedef {(typeof SIZES)[number]} Size */ | type Size = (typeof SIZES)[number]; |
Examples
/**
* @typedef {object} Order
* @property {string} id
* @property {"pending" | "shipped" | "delivered"} status
* @property {{ sku: string, quantity: number }[]} lines
*/
/** @typedef {Order["status"]} OrderStatus */
/** @typedef {Order["lines"][number]} OrderLine */
/** @param {OrderStatus} status */
export function isOpen(status) {
return status !== "delivered";
}
/** @param {OrderLine} line */
export function lineLabel(line) {
return `${line.quantity} × ${line.sku}`;
}
isOpen("pending");
lineLabel({ sku: "TEE-01", quantity: 2 });interface Order {
id: string;
status: "pending" | "shipped" | "delivered";
lines: { sku: string; quantity: number }[];
}
type OrderStatus = Order["status"];
type OrderLine = Order["lines"][number];
export function isOpen(status: OrderStatus) {
return status !== "delivered";
}
export function lineLabel(line: OrderLine) {
return `${line.quantity} × ${line.sku}`;
}
isOpen("pending");
lineLabel({ sku: "TEE-01", quantity: 2 });jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /** @typedef {{ id: string, status: string }} Order */
/** @param {Order["stauts"]} status */error TS2339: Property 'stauts' does not exist on type 'Order'.
export function isOpen(status) {
return status !== "delivered";
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} export const SIZES = /** @type {const} */ (["S", "M", "L", "XL"]);
/** @typedef {(typeof SIZES)[number]} Size */
/** @param {Size} size */
export function stockFor(size) {
return SIZES.indexOf(size);
}
stockFor("XL");
stockFor("XXL");error TS2345: Argument of type '"XXL"' is not assignable to parameter of type '"S" | "M" | "L" | "XL"'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} The key is checked
The index must be a key of the type. Order["stauts"] is TS2339, reported on the JSDoc line, as the second example shows. That makes indexed access safer than copying a property's type by hand.
Values and their type from one list
const SIZES = /** @type {const} */ (["S", "M", "L", "XL"]) keeps the strings as literals, and (typeof SIZES)[number] is "S" | "M" | "L" | "XL". The array is used at run time (for a dropdown, say) and the type comes from it, so the list exists once.
Gotchas
- The property name goes in quotes:
Order["status"].Order.statusis not a type. - Indexing with a union,
Order["id" | "status"], gives the union of those properties' types.
Questions
How do I get the type of an array element in JSDoc?
Index the array type with number: {Order["lines"][number]}, or {(typeof items)[number]} for an array value.
Sources
- Indexed Access Types · TypeScript handbook
Last reviewed 20 October 2026.