TypeScript is a powerful superset of JavaScript that provides static typing for enhanced code quality and maintainability. One of its key features is the ability to define and use various types, and among them is the lesser-known unknown type.
In this article, we’ll explore TypeScript’s “unknown” type, its properties, use cases, and how it compares to the more commonly used “any” type.
What is the unknown Type?
The “unknown” type is a relatively new addition to TypeScript, introduced with TypeScript 3.0. It serves as a type-safe counterpart to the more permissive “any” type. While “any” allows for maximum flexibility by permitting assignments of any type, “unknown” is more restrictive. Here are the key characteristics of the “unknown” type:
- Anything is Assignable to unknown: You can assign values of any type to a variable declared with the unknown type. This means that during compilation, TypeScript won’t raise errors for such assignments.
let random: unknown;
random = 'Hello World!';
random = {};
random = 7;
random = null;
// ...and so on
- unknown isn’t Assignable to Anything Else: You cannot assign a variable of type unknown to another typed variable without either a type assertion or control-flow-based narrowing. Attempting to do so will result in a compilation error.
let random: unknown;
let foo: unknown;
let bar: any;
foo = random; // Correct
bar = random; // Correct
let stringValue: string;
stringValue = random; // Compilation error
- unknown is Assignable to Object: Interestingly, you can assign a variable of type “unknown” to a variable of type “Object” (or even {}). This is because in JavaScript, almost anything can be treated as an object, except for primitive types like string, number, boolean, undefined, symbol, bigint, and null.
let objectValue: Object;
objectValue = random; // No compilation error
Using unknown in Intersection and Union Types
The behavior of the unknown type in intersection and union types is worth noting:
- Intersection Types: When you use “unknown” in an intersection type, it behaves in a way that the resulting type will “absorb” or take precedence over the unknown”type. Essentially, it removes the unknown type from the resulting type. For example:
type Type1 = unknown & string; // Results in "string"
type Type2 = unknown & string[]; // Results in "string[]"
- Union Types: Conversely, when you use “unknown” in a union type, it absorbs all the other types, resulting in the type being “unknown” itself. This makes it pointless to define a union type containing “unknown” as it will always default to “unknown.” For example:
type Type1 = unknown | string; // Results in "unknown"
type Type2 = unknown | string[]; // Results in "unknown"
Differences Between “unknown” and “any”
While “unknown” and “any” may seem similar, there are significant differences to consider:
- Assignability: “any” is highly assignable, allowing values to be assigned to variables of various types with minimal restrictions. In contrast, “unknown” is more restrictive, limiting assignments to other variables with the “unknown” type or requiring type assertions.
- Calling Methods and Constructors: “any” allows you to call methods or create instances of itself without compilation errors. “unknown” prohibits such behavior and raises compilation errors, which can prevent runtime errors.
When to Use “unknown” and “any”
The choice between “unknown” and “any” depends on your development goals:
- Use any When Flexibility is Key: If you want maximum flexibility and are willing to handle potential runtime errors, “any” is a suitable choice. However, be cautious when using “any” to maintain code quality.
- Use unknown for Predictable Code: “unknown” is the better choice for writing more predictable code. It encourages developers to handle type-related issues during development rather than at runtime, reducing unexpected errors.
People also love to read about TypeScript type vs interfaces and TypeScript omit type.
Converting unknown to Other Types
Converting a variable of type “unknown” to other types in TypeScript requires type assertions or careful checking. Here are some conversion examples:
- To Interface Type: You can convert “unknown” to an interface type using type assertions:
nterface Car {
model: string;
brand: string;
}
let random: unknown = { brand: 'Ford', model: 'Mustang' };
let car: Car = <Car>random
i;
- To String Type: You can convert “unknown” to a string type using type assertions or the String constructor:
let random: unknown = 'Hello World!';
let stringValue1: string = random as string;
let stringValue2: string = String(random);
- Remember to check the type of the “unknown” variable before performing these conversions to avoid runtime errors.
Conclusion
TypeScript’s “unknown” type is a valuable addition that offers enhanced type safety over the more permissive “any” type. It encourages developers to write more predictable and robust code while still allowing flexibility when needed.
By understanding the properties and use cases of “unknown,” you can make informed decisions about when to use it in your TypeScript projects, ultimately leading to more reliable and maintainable code. Here is another interesting article covering the most efficient ways to convert strings to numbers.
Leave a Reply