When Type Safety Might Not Be the Best Choice
Having a statically type language like TypeScript changed the whole industry after it’s launch in 2012 and multiple other languages followed the same path of introducing statically typed approach by solving issues like:
- Catch type-related errors at compile-time.
- Early error detection to fix issues early in the development process.
- Enhanced Code Readability it becomes clearer what types of data variables and functions expect and return.
- Code maintainability it enforced type system encourages developers to write more structured and maintainable code.
- Easier Refactoring helps identify areas of the codebase that need to be updated when refactoring or making changes.
- The list goes on but I am here to talk why it’s not always a must and in few cases can be deemed as an “overkill”.
Small scripts or prototypes
When creating certain throwaway scripts or prototypes certain emphasis may be on speed and simplicity rather then robust type checking.
function calculateSum(a, b) { return a + b; const num1 = 5; const num2 = 10; const result = calculateSum(num1, num2); console.log("Result:", result);
function calculateSum(a: number, b: number): number { return a + b; } const num1: number = 5; const num2: number = 10; const result: number = calculateSum(num1, num2); console.log("Result:", result);
Simplicity and Less Boilerplate: Looking at both side by side JS in general has always less boilerplate. While I agree boilerplate is not an issue for big applications but simple scripts is a different story.
Faster iteration: Lack of type annotation allows for faster development.
Ease of Learning: This applies to people who are new to TypeScript and there is a visible learning curve.
Flexibility in Inputs: While this may introduce potential issues, it can also be beneficial during quick prototyping when you want to test different input scenarios without worrying about strict type checks.
In general JavaScript might be more suitable for small scripts and prototypes but TypeScript shines when it comes to larger, more complex projects.
Exploratory coding
Let’s consider creating and manipulating a simple object.
const person = { name: "John Doe", age: 30, email: "john.doe@example.com", }; console.log("Person:", person);
interface Person { name: string; age: number; email: string; } const person: Person = { name: "John Doe", age: 30, email: "john.doe@example.com", }; console.log("Person:", person);
Lightweight Syntax: In JS, there is less overhead in terms of syntax when defining objects.
Flexibility in Object Modification: During experimentation, you might frequently change the object structure and it can help freely modify the object
Overall, JavaScript’s dynamic nature can be advantageous during initial experimentation but same as talked before TS exels when project grows in complexity.
Parsing or manipulating text
Let’s consider an example where we need to manipulate a string containing a date in a specific format and extract the day, month, and year from it.
function parseDate(dateString) { const [day, month, year] = dateString.split("/"); return { day, month, year }; } const dateStr = "30/07/2023"; const parsedDate = parseDate(dateStr); console.log("Parsed Date:", parsedDate);
function parseDate(dateString: string) { const [day, month, year] = dateString.split("/"); return { day, month, year }; } const dateStr: string = "30/07/2023"; const parsedDate = parseDate(dateStr); console.log("Parsed Date:", parsedDate);
In our simple example JavaScript excels due to it’s simplicity and flexibility. Since text manipulation tasks are typically straightforward and involve minimal risk of type-related errors, TypeScript’s static type checking might not provide significant advantages in this particular case.
If your application is just String based like few input forms and no complex typing system then as well TS can seem like an overkill in my opinion.
Language interoperability
Language interoperability refers to the ability of different programming languages to work together in the same project or system.
// A simple JavaScript function without type annotations function greet(name) { return `Hello, ${name}!`; } // Export the function to make it accessible outside the module module.exports = greet;
// Import the JavaScript function using require syntax const greetJS = require('./library.js'); // TypeScript code that uses the JavaScript function function sayHello(name: string): string { // Invoke the JavaScript function const greeting = greetJS(name); return greeting; } // Usage example const name = "John Doe"; const message = sayHello(name); console.log(message);
The JavaScript example is super simple and has no added overhead the TypeScript approach needs require syntax(commonly used in Node.js).
TypeScript’s type safety benefits can be gradually introduced to existing JavaScript codebases by using declarations and type annotations
In general TypeScript offers a lot of benefits but if you know the project complexity won’t evolves and becomes mores significant it just adds overhead, development speed will drop and maintainability might not outweigh the additional maintenance efforts required for maintaining type annotations.
In own work experience often just strings are passed in and the app is really simple and following the hype train of statically typed language may not be always the best choice. Simple dynamically typed language like JS or Python can be sufficient enough and if needed you can always migrate later on if your sure type-safety will.
We developers tend to add additional complexity where it is not always needed.