A literal type allows exactly one value: the type "GET" accepts only the string "GET". On their own they are rarely useful; joined into a union, {"GET" | "POST" | "DELETE"}, they list every value a parameter may take, and TypeScript rejects anything else at the call site.
String, number and boolean literals all work, and editors offer the allowed strings as completions while you type the argument.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| String literals | /** @param {"GET" | "POST"} method */ | (method: "GET" | "POST") |
| Number literals | /** @typedef {1 | 2 | 3 | 4 | 5} Stars */ | type Stars = 1 | 2 | 3 | 4 | 5; |
| A boolean literal | /** @param {true} verified */ | (verified: true) |
Examples
/**
* @param {"GET" | "POST" | "DELETE"} method
* @param {string} url
*/
export function request(method, url) {
return fetch(url, { method });
}
request("GET", "/api/cart");
request("PATCH", "/api/cart");error TS2345: Argument of type '"PATCH"' is not assignable to parameter of type '"GET" | "POST" | "DELETE"'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /** @param {"GET" | "POST"} method */
export function request(method) {
return method;
}
const fixed = "GET";
request(fixed);
let changing = "GET";
request(changing);error TS2345: Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.
/** @type {"GET" | "POST"} */
let typed = "GET";
request(typed);
export { changing, typed };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /** @typedef {1 | 2 | 3 | 4 | 5} Stars */
/**
* @param {Stars} stars
* @param {true} verified only verified reviews are shown
*/
export function showReview(stars, verified) {
return `${"★".repeat(stars)} ${verified ? "(verified)" : ""}`;
}
showReview(4, true);
showReview(6, true);error TS2345: Argument of type '6' is not assignable to parameter of type 'Stars'.type Stars = 1 | 2 | 3 | 4 | 5;
export function showReview(stars: Stars, verified: true) {
return `${"★".repeat(stars)} ${verified ? "(verified)" : ""}`;
}
showReview(4, true);
showReview(6, true);error TS2345: Argument of type '6' is not assignable to parameter of type 'Stars'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} When a value stops being a literal
TypeScript infers a literal type for a const (const fixed = "GET" is "GET"), but a let is widened to string, because it could be reassigned to any string. Passing that let to a parameter of type "GET" | "POST" fails with TS2345, as the second example shows.
Give the let the union type with @type, or use const. For object properties, which are widened the same way, a const assertion keeps the literals: /** @type {const} */ ({ method: "GET" }).
Naming a set of literals
Give a union of literals a name with @typedef when more than one function uses it: /** @typedef {"draft" | "live"} Status */. The name shows up in hovers and error messages, which reads better than the expanded union.
Gotchas
- Literal types are checked only when TypeScript can see the value. Data from JSON or a form is a plain
stringuntil you check it against the allowed values. - Template literal types extend the idea to patterns of strings, such as every string that ends in
px.
Questions
How do I restrict a JSDoc parameter to a few strings?
Write the allowed values as a union of string literals: @param {"small" | "medium" | "large"} size.
Sources
- Everyday Types: literal types · TypeScript handbook
- Narrowing · TypeScript handbook
Last reviewed 20 October 2026.