«Type 'string' is not assignable to type» — what is it and why are you here?
\n\nIf you've ever written in TypeScript, you've likely encountered red underlining in the code editor and a message:
\n\nType 'string' is not assignable to type 'SomeType'.\n\nThis error is a real «hello» from strict typing. It scares beginners, but in fact, it is the developer's best friend. In this article, we will break down why the Type 'string' is not assignable to type error occurs, how to fix it, and what approaches exist for working with string literals, union types, and generics. The article is written for the educational site pythonlib.ru, but the examples are entirely in TypeScript.
\n\n1. The root of the problem: why does TypeScript complain about strings?
\n\nTypeScript is a superset of JavaScript that adds static typing. When you write:
\n\nlet role: 'admin' | 'user' = 'admin';\nrole = 'moderator'; // Error: Type '"moderator"' is not assignable to type '"admin" | "user"'\n\n\nTypeScript understands that the variable role can only accept two values: 'admin' or 'user'. When you try to assign 'moderator', the compiler throws an error. But why does it say «Type 'string' is not assignable to type»?
The thing is, the string literal 'moderator' has the type string, while the expected type is 'admin' | 'user'. TypeScript compares types, not values. It sees: «You're giving me a regular string, but I expect specific strings». Hence the message.
1.1. Simple example for understanding
\n\nConsider a basic case:
\n\ntype Status = 'active' | 'inactive';\n\nfunction updateStatus(status: Status) {\n console.log(status);\n}\n\nconst myStatus = 'active';\nupdateStatus(myStatus); // OK\n\nconst anotherStatus = 'pending';\nupdateStatus(anotherStatus); // Error: Type 'string' is not assignable to type 'Status'\n\n\nIn the last case, the variable anotherStatus is inferred as string, not as 'pending'. TypeScript doesn't know that 'pending' is a literal. It only sees the type string. You can fix this by explicitly specifying the type:
const anotherStatus: 'pending' = 'pending'; // Now it works\n\n\n2. Approach comparison: how to work around or fix the error
\n\nThere are several ways to deal with the Type 'string' is not assignable to type error. We'll compare them by simplicity, safety, and performance.
\n\n2.1. Approach 1: as const — freezing the literal
\n\nThe most elegant way is to use as const. It «freezes» the value as a literal:
const myStatus = 'active' as const;\nupdateStatus(myStatus); // OK\n\n\nPros: simple, readable, safe.
\nCons: works only with const, not with let.
2.2. Approach 2: Type Assertion (as) — explicit casting
\n\nYou can tell TypeScript: «I know what I'm doing»:
\n\nconst someString: string = 'active';\nupdateStatus(someString as Status); // OK\n\n\nPros: quick fix.
\nCons: you disable type checking. If you pass an invalid value, the error will only appear at runtime.
2.3. Approach 3: Type Guard
\n\nLet's write a function that checks whether a string is a valid status:
\n\nfunction isStatus(value: string): value is Status {\n return value === 'active' || value === 'inactive';\n}\n\nfunction safeUpdate(value: string) {\n if (isStatus(value)) {\n updateStatus(value); // TypeScript knows that value is Status\n } else {\n throw new Error('Invalid status');\n }\n}\n