Static typing is a programming language feature that requires you to strictly define the structure and data types of the code you write. While it’s often more work for the developer, it leads to much cleaner and understandable codebases in the long run.
What Is Static Typing?
In a dynamically typed language, you define everything with var. There are no predefined types like string or int; the variable simply contains a value:
This might not be an issue for local variables like this, but once you start working with more complex data, you start to hit a problem. Functions don’t give you any information about what arguments you should pass it, beyond the function names themselves. If you try to pass it junk arguments, it’ll accept them, and if the function’s code is expecting a string instead of a number, it may throw an error.
But, in a statically typed language like C#, the types are set before you hit compile. It’s immediately much more clear what the function wants from you, and if you try to pass it something it didn’t ask for, the compiler will throw an error.
Beyond that, it’s also much more clear what the function actually does, because the function will have a return type. Without prior understanding of the codebase, or even taking a single look at the source code, you can infer what it’s supposed to do from the return type, function name, and input parameters.
This static typing applies everywhere, and usually pretty aggressively. Anytime you define a variable, you must specify a type name. All functions must have fully specified type names for the arguments and return type. If you’re switching from dynamically typed languages, you won’t be allowed to just write var without thinking.
Why Is Static Typing Useful?
If this seems like extra work, it certainly is. But it has some great benefits in the long run.
The most important feature for developers is compile-time error checking. If you code wrong, and try to use a different type than intended, or try to call a method that doesn’t exist, the compiler will yell at you. In a dynamically typed language like JavaScript, it would simply throw an error at runtime—not good. In C#, you’ll get warnings if you try to do something you shouldn’t, like call a non-existent method.
This helps catch errors early, and reduces the number of buggy commits your developers will be making.
Beyond catching errors in sloppy code, static typing can make up for the extra work by allowing you to code more efficiently in the future. Whenever you use a function, or try to access properties of a class, your IDE can go look up what types the function takes, or which methods the class implements. This makes working with code you didn’t write a lot easier.
Statically typed code can also run faster. It doesn’t matter if the language is interpreted or compiled; either way, knowledge of static types can allow for additional machine code optimization, so your program isn’t using more memory or clock cycles than it really needs.
For JavaScript, you actually have the option of whether or not you want to use static typing. TypeScript is a superset of JavaScript that’s backed by Microsoft, made specifically to add static typing to the language. It’s a preprocessed language, so it’s all JavaScript at the end of the day, but it brings all the IDE benefits of static typing. After all, JavaScript began as a basic scripting language, but today it powers some very complex web applications. The need for static typing in complicated projects was clear, and so TypeScript was born.
Is There Any Reason to Prefer Dynamic Typing?
This problem isn’t completely black and white. Every language will have varying levels of statically checked features. These can even be added after the fact with linters and other static analysis tools, even for very dynamic languages like JavaScript.
For the most part, the many benefits of static typing outweigh the few downsides, so if you have the option (like in the case of TypeScript vs. JavaScript), most large projects will choose static typing. However, there are diminishing returns once it starts becoming to restrictive.
For some people, particularly solo coders or startups wanting to prototype quickly, there are many cases where dynamic typing can be superior. Dynamic typing is, of course, a lot more flexible. Removing the need to specify types allows quicker writing of more concise code. This is especially helpful for scripting languages like JavaScript and Python. For rapid prototyping, dynamic typing can help a lot.
Because nothing is specified at compile time, dynamically typed languages often use duck typing to determine what an object can do. Checking if a method exists before calling it allows different kinds of input to be passed to the function, which can enable more flexible polymorphism.
Overall, it’s all personal preference, so it’s not possible to say that static typing is better all of the time. It comes down to you and your project’s needs, and also any other features of the languages you’re considering using.
Strongly Typed vs. Weakly Typed
Despite sounding very similar, “strongly vs. weakly typed” and “statically vs. dynamically typed” are two different concepts.
Strongly typed means that the language doesn’t do many implicit type conversions or type coercions. For example, C# is a strongly typed language. If you want to pass an int to a function that expects a float, you’ll get an error.
This can be fixed with an explicit conversion, called a cast. Strongly typed languages require more casts. Weakly typed languages will do automatic conversions. Again, it’s not black and white here, and some implicit conversions do exist in C# and other strongly typed languages, and you can define your own implicit conversions between custom types as well.
Generally, strong typing leads to less confusion overall, but implicit conversions where it makes sense are useful. For example, converting int to float automatically is usually fine, as no data is changed beyond switching to a different type. Converting a float to an int would need some form of rounding to get rid of the decimal places.
Weak typing can lead to confusion in some extreme cases. For example, JS is famous for its generous implicit conversions: You can add a number to a string, and get a string as a result. But if you multiply a number and a string, it parses the string into a number, and returns NaN if it can’t be parsed.