TypeScript Unknown in Depth
An unknown value can hold anything, and no part of it can be used before a runtime check narrows it. Parsing with unknown turns outside data into typed values one verified field at a time.
Parsing JSON into unknown
The parse result is stored as unknown. Presence checks with in and type checks with typeof run before either field is read.
const rawText = '{"title":"Dune","pages":412}';
const data: unknown = JSON.parse(rawText);
if (typeof data === 'object' && data !== null && 'title' in data && 'pages' in data) {
if (typeof data.title === 'string' && typeof data.pages === 'number') {
console.log(data.title);
console.log(data.pages);
}
}One function, many shapes
A parameter typed unknown handles each runtime shape in its own branch. Each branch narrows the value before using it.
function describeValue(value: unknown): string {
if (typeof value === 'string') {
return 'text: ' + value;
}
if (typeof value === 'number') {
return 'count: ' + value;
}
if (Array.isArray(value)) {
return 'list of ' + value.length;
}
return 'something else';
}
console.log(describeValue('hello'));
console.log(describeValue(42));
console.log(describeValue([1, 2, 3]));
console.log(describeValue(true));The catch variable stays unknown
Under strict mode the caught value has type unknown. Reading its message without a narrowing check fails to compile.
try {
throw new Error('boom');
} catch (e) {
console.log(e.message);
}Example
function parseMessage(rawText: string): string {
try {
const data: unknown = JSON.parse(rawText);
if (typeof data !== 'object' || data === null) {
throw new Error('payload is not an object');
}
if ('message' in data && typeof data.message === 'string') {
return data.message;
}
throw new Error('payload has no message');
} catch (e) {
if (e instanceof Error) {
return 'failed: ' + e.message;
}
return 'failed: unknown error';
}
}
console.log(parseMessage('{"message":"bad token"}'));
console.log(parseMessage('[1, 2]'));Key points
- unknown accepts a value of any shape, and the checker allows no use before narrowing.
- JSON.parse returns any, so storing the result in an unknown variable restores the checks.
- The typeof operator and the in operator narrow an unknown value one fact at a time.
- Under strict mode, the variable caught by a catch block has type unknown.
- An instanceof Error check narrows the caught value before its message can be read.
In this example, the payload earns trust through object, presence and string checks, and the catch block narrows the error with instanceof before reading its message.
Try it Yourself
Edit the code, then press Run.
Running is simulated · TypeScript Playground
Exercise
Why store a JSON.parse result in an unknown variable instead of leaving it as any?