Both dynamic and static languages rely on types. That is, definitions of data structures and their behaviors to ensure that programs are correct. It's just that the two kinds of languages validate that in different ways. Dynamic languages aim to be much more forgiving at development time, relying on the concept of duck typing to validate that a particular object can be used in a certain way. Duck typing refers to the idea that if it looks like a duck, walks like a duck, and quacks like a duck, well, it must be a duck.
In other words, if my code expects an object that has a method called "quack" on it, and I get an object that has a method named "quack", well, that's good enough for me. I don't need to validate anything else about that object. The net result of this approach is that tools don't have enough information to catch errors before the application runs. For example, if I've accidentally typed the wrong name "quake", rather than "quack", this means that errors are only ever caught while the application is running after it's too late to do anything about it.
Statically typed languages, on the other hand, are much more rigid. They aim to catch development errors before the code is even executed. And they do this by imposing restrictions on how you can interact with objects, forcing you to clearly specify everything about the object that you're going to interact with. In the static typing world, you can't just call a "quack" method on any object. You first need to explicitly define a type that has that "quack" method, as well as any parameters that need to be passed into that method, not to mention the value that the "quack" method will return to its callers.
Only then can you use that instance as a parameter, or create an instance of that class to pass around to other objects or methods. With all this information explicitly provided, the tooling is able to easliy tell me when I've misplaced a call to the "quack" method well before my application is running. Heck, with modern tools, it's likely to take less than a second for me to find out that I've done something wrong. If it sounds like I'm making a case for one approach over the other, I'm not. Each of the typing approaches lends itself to a different set of scenarios.
And I don't want to wait until runtime to find out. In that case, I'll use TypeScript language features to make that very clear right in my code and TypeScript will validate that assertion before my code executes. This all comes at a cost, of course. You've got to define types in order to use them. And that means writing more code. You just have to weigh the cost of writing that code with the value of finding out about these kinds of issues before your code executes. For many people, and many scenarios, having this piece of mind is well worth the extra work of defining the types.
And if finding out about code issues as early as possible isn't enough, having to explicitly define the types of the object you work with, also tends to make your code easier to understand and maintain. Especially if you have multiple developers working on the same code base. In cases such as these, static types tend to have an illuminating effect, helping developers understand what they can and can't do with a particular object. But perhaps the best thing about TypeScript, is that you don't always have to use static types.
- What is TypeScript?
- Installing TypeScript
- Creating a TypeScript project
- Reviewing ES6 language features
- Defining custom and anonymous types
- Defining and implementing TypeScript classes
- Working with generics
- Organizing code with namespaces
- Switching modules
- Importing modules
- Debugging TypeScript
- Implementing decorators