Advanced Types in TypeScript
Genne23v
Posted on March 19, 2023
Strongly typed languages increase the safety of programs. It doesn't mean that strongly typed languages are always better than weakly typed languages. Weakly typed languages can reduce the development time. So programmers should choose a programming language based on the purpose of the program. Although I contributed some of Typescript projects, but I didn't have much knowledge about Typescript typing. I learned some of very useful typing techniques during Starchart code review.
When using the same type with different property names
You could face the situation that it doesn't make sense to have two different type names while only small portion of the properties varies. My DNS module in Starchart is a good example to explain this instance. At the beginning, we use the variable name
as any type of domains. But in our app, this name could be subdomain
or fully qualified domain name
which can be shortened to fqdn
. This is very confusing when writing a code to use the function. You don't have any idea whether you are going to get subdomain
or fqdn
which could result in a wrong implementation or frustrating the writer to look up all the code to figure what it actually is. So we can do something like this.
type Name = { subdomain: string } | { fqdn: string };
interface BaseDnsRequestData {
type: string;
value: string;
}
type DnsRequestData = BaseDnsRequestData & Name;
So DnsRequestData
can have either subdomain
or fqdn
. When you extract the data, Typescript knows what type is passing only in runtime. So you should extract the data as below.
let name;
if ('subdomain' in data) {
name = data.subdomain;
} else {
name = data.fqdn;
}
When type naming is not necessary
Sometimes it's better not to name the type when passing data is obvious or varying similar names is more confusing. So you can instead of defining as below,
interface Record {
type: string;
name: string;
value: string;
description: string;
ports: string;
}
type DnsRequestData = {
type: Record['type'];
name: Record['name'];
value: Record['value'];
description?: Record['description'];
ports?: Record['ports'];
}
You can simplify the type without naming.
Pick<Record, 'type' | 'name' | 'value'> & Partial<Pick<Record, 'description' | 'ports'>>
Conclusion
It was really good for me not just to learn these techniques, but also to help me to write better code. It seems not important for someone who develops something quickly, but typing is very important when many contributors or developers are working together. It finds the potential errors quickly and gives an idea of what this code does. It also takes a lot of learning from the experienced. I never thought about this kind of problems when I was working alone. Having the experienced developers' feedback is really helpful to learn how to write better code. Thanks for reading my article!
Posted on March 19, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.