error TS2550: Property 'at' does not exist on type 'string[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2022' or later. is reported when code calls a built-in method that the checker knows was added in a later ECMAScript year than the libraries it loaded. The message names the year that added it.
It is a version question, not a typo. The checker only knows what your config tells it about the runtime: if target (or lib) says ES2020, methods from 2021 and 2022 are reported, whether or not your Node.js or browsers have them.
At a glance
| Code | TS2550 |
|---|---|
| Message | Property '{0}' does not exist on type '{1}'. Do you need to change your target library? Try changing the 'lib' compiler option to '{2}' or later. |
| TypeScript's category | error |
| Listed under | Unknown names and members |
| Depends on | target, lib |
| 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
/** @param {string[]} tags */
export function lastTag(tags) {
return tags.at(-1);error TS2550: Property 'at' does not exist on type 'string[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2022' or later.
}
/** @param {string} slug */
export function titleFromSlug(slug) {
return slug.replaceAll("-", " ");error TS2550: Property 'replaceAll' does not exist on type 'string'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2021' or later.
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2020",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} What causes it
targetorlibnames an older year than the method (.at()is ES2022,replaceAllES2021,Object.entriesES2017,includesES2016).- No
targetat all, which meanses5in TypeScript 5.9; thenMapandPromisefail too, see TS2583.
How to fix it
Raise target when every runtime has the method
Set target to the year the message names or later. Before you do, check that every runtime you support has the method; MDN's compatibility tables list browser and Node.js versions.
/** @param {string[]} tags */
export function lastTag(tags) {
return tags.at(-1);
}
/** @param {string} slug */
export function titleFromSlug(slug) {
return slug.replaceAll("-", " ");
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} Or write it the older way
If you support runtimes without the method, keep the target and use the older equivalent: tags[tags.length - 1] for .at(-1), split("-").join(" ") or a global regular expression for replaceAll. A polyfill works too, but the checker still needs the newer lib to know the method exists.
Gotchas
libset explicitly overrides the librariestargetwould pick, so raisingtargetalone does nothing iflibnames an old year.- The checker never adds polyfills or rewrites the code;
noEmitprojects run the JavaScript exactly as written.
Sources
- TSConfig Reference: target · TypeScript
- Array.prototype.at() · MDN Web Docs
- diagnosticMessages.json (TypeScript 5.9.3) · TypeScript on GitHub
Last reviewed 20 October 2026.