TYPESCRIPT

TypeScript unknown Type: Syntax, Usage, and Examples

The unknown type represents a value that could be anything, but TypeScript won’t let you use it until you prove what it is. It’s the safer alternative to any when you don’t know the type ahead of time.


How to Use the unknown type

You can assign any value to unknown, but you can’t access properties or call methods on it without narrowing.

Basic syntax

letinput:unknown;

input ="hello";
input =42;
input = {online:true };
input =null;

That freedom looks like any, but unknown comes with one big rule: you must check the value before using it.

Using unknown forces type checks

This will not compile:

letvalue:unknown ="mimo";
console.log(value.toUpperCase());

TypeScript blocks it because value might not be a string.

To fix it, narrow the type:

letvalue:unknown ="mimo";

if (typeof value ==="string") {
console.log(value.toUpperCase());
}

Assigning unknown to a specific type

You can assign a known type to unknown, but you can’t assign unknown to a known type without checking first.

This works:

lettitle:string ="Dashboard";
letdata:unknown = title;

This does not:

letdata:unknown ="hello";
letname:string = data;// Type error

To safely assign it, narrow it:

letdata:unknown ="hello";

if (typeof data ==="string") {
letname:string = data;
}

Using unknown in functions

A common pattern is to accept an unknown input and validate inside the function.

functionprintLength(value:unknown) {
if (typeof value ==="string") {
console.log(value.length);
  }else {
console.log("Not a string, no length to print.");
  }
}

printLength("Vienna");
printLength(99);

unknown arrays

unknown[] means “an array of values, but I don’t know what each value is yet.”

constitems:unknown[] = [1,"two",false];

for (const itemof items) {
if (typeof item ==="string") {
console.log(item.toUpperCase());
  }
}


When to Use the unknown type

Use unknown when you truly don’t know what will arrive at runtime, but you still want TypeScript to keep you honest.

1) Working with API responses or JSON

APIs can change, or they can return weird data when something goes wrong. unknown makes you validate before using it.

asyncfunctiongetUserData():Promise<unknown> {
const response =awaitfetch("/api/user");
return response.json();
}

Later, you narrow it before accessing fields.

2) Accepting user input from forms

Form inputs often come in as strings, but you might treat them as numbers or booleans after parsing.

functionparseAge(input:unknown) {
if (typeof input ==="string") {
const numberAge =Number(input);
if (!Number.isNaN(numberAge)) {
return numberAge;
    }
  }
returnnull;
}

unknown helps prevent accidentally treating a random value as a valid number.

3) Handling errors safely in catch blocks

In modern TypeScript, catch (error) is treated as unknown in many setups.

try {
JSON.parse("broken json");
}catch (error:unknown) {
if (errorinstanceofError) {
console.log(error.message);
  }else {
console.log("Something unexpected happened.");
  }
}

This avoids assuming error always has .message.

4) Writing reusable utility functions

Generic utilities often accept inputs from lots of places. unknown makes them safer by forcing checks.

functionsafeToString(value:unknown):string {
if (typeof value ==="string")return value;
if (typeof value ==="number")return value.toString();
return"Unsupported value";
}


Examples of the unknown type

Here are some realistic examples that show how unknown protects you from easy mistakes.

Example 1: Parsing JSON safely

const raw ='{"name":"Lea","role":"admin"}';
constdata:unknown =JSON.parse(raw);

if (typeof data ==="object" && data !==null &&"name"in data) {
const user = dataas {name:string };
console.log(user.name);
}

This is more work than any, but it stops you from doing data.name on a number, null, or something unexpected.

Example 2: Narrowing with typeof checks

functionformatValue(value:unknown) {
if (typeof value ==="string") {
return value.trim();
  }

if (typeof value ==="number") {
return value.toFixed(2);
  }

return"Unsupported type";
}

console.log(formatValue("  5  "));
console.log(formatValue(3.5));
console.log(formatValue(true));

TypeScript understands each branch, so you get safe method access like .trim() and .toFixed().

Example 3: Validating a dynamic object

Imagine you receive a settings object from localStorage.

conststored:unknown =JSON.parse('{"theme":"dark","fontSize":16}');

typeSettings = {
theme:string;
fontSize:number;
};

functionisSettings(value:unknown): value isSettings {
if (typeof value !=="object" || value ===null)returnfalse;

const obj = valueasRecord<string,unknown>;

return (
typeof obj.theme ==="string" &&
typeof obj.fontSize ==="number"
  );
}

if (isSettings(stored)) {
console.log(stored.theme);
console.log(stored.fontSize);
}else {
console.log("Invalid settings format, using defaults.");
}

That isSettings function is a type guard. It tells TypeScript, “After this check, you can trust the type.”

Example 4: unknown in event-driven code

Sometimes you get data from a message event (like browser messaging or WebSocket).

functionhandleMessage(payload:unknown) {
if (typeof payload ==="string") {
console.log("Message:", payload);
return;
  }

if (typeof payload ==="object" && payload !==null) {
console.log("Object message received.");
return;
  }

console.log("Unsupported payload type.");
}

You can support multiple input shapes without letting anything slide through silently.


Learn More About the unknown type

unknown is powerful, but it becomes much easier once you know the patterns TypeScript expects.

unknown vs any

The difference is simple:

  • any lets you do anything, even unsafe things
  • unknown makes you check first

Example with any:

letdata:any ="hello";
console.log(data.toUpperCase());// allowed

Example with unknown:

letdata:unknown ="hello";
console.log(data.toUpperCase());// blocked

With unknown, TypeScript won’t let you accidentally call string methods on a number.

Common narrowing techniques

Here are the most common ways to narrow a value:

typeof checks

functioncheck(value:unknown) {
if (typeof value ==="boolean") {
return value ?"yes" :"no";
  }
return"not a boolean";
}

instanceof checks

Useful for error objects, Dates, and class instances.

functionhandleError(error:unknown) {
if (errorinstanceofError) {
console.log(error.message);
  }
}

in operator for objects

Good for checking properties.

functionhasId(value:unknown) {
if (typeof value ==="object" && value !==null &&"id"in value) {
const obj = valueas {id:unknown };
return obj.id;
  }
returnnull;
}

Type guards make code cleaner

Type guards are reusable checks you can call everywhere.

typeProduct = {
id:number;
name:string;
};

functionisProduct(value:unknown): value isProduct {
if (typeof value !=="object" || value ===null)returnfalse;
const obj = valueasRecord<string,unknown>;
returntypeof obj.id ==="number" &&typeof obj.name ==="string";
}

Then you get safe access:

constinput:unknown = {id:1,name:"Keyboard" };

if (isProduct(input)) {
console.log(input.name.toUpperCase());
}

unknown works well with generics

Sometimes you want a function that can accept unknown input, then return a known type after validation.

function parseJSON<T>(raw:string): T {
returnJSON.parse(raw)as T;
}

typeUser = {name:string };
const user = parseJSON<User>('{"name":"Noor"}');
console.log(user.name);

This uses a type assertion, so you still need to be careful, but it’s a common pattern for controlled data.

A practical rule of thumb

Use unknown when:

  • you receive data from outside your code
  • you parse JSON
  • you handle errors
  • you accept flexible input in a shared utility

Use a specific type or a union type when:

  • you know the shape of the data
  • the value can only be one of a few types

If unknown feels annoying at first, that’s normal. The extra checks are the point.


Summary

The unknown type is a safe way to represent values you don’t know yet. You can assign anything to it, but you must narrow the type before using it.

It’s a great fit for API responses, user input, error handling, and reusable utilities, especially when you want TypeScript to catch mistakes before runtime.