We crunched the data from SonarLint to discover the top 5 most common TypeScript issues. In this 5 part series, we outline each issue and how to avoid it.
We encourage you to install SonarLint in your editor and follow along with the examples below. Make sure you have a valid tsconfig.json
in your working directory or run npx tsc --init
to create one.
In at Nº 5: Optional property declarations
Optional object properties are properties that can hold a value or be undefined
. In TypeScript there are a few ways to declare an optional object property.
You can use a union, like this:
This might look fine, but if you check it out in your editor you’ll see that the TypeScript compiler doesn’t agree. To fulfill the type definition you need to provide the address
property on the object even if it is undefined
.
Alternatively, you can use the optional property syntax like this:
Now TypeScript is happy with this, which means that using the optional property syntax must be behaving differently to the union type we started with.
With the first example, we are requiring that the property is always defined, even when the value itself is undefined
. This is important in cases when you enumerate the properties of an object. That is, whether the address
property is set to undefined
or to a string, accessing Object.keys(john).length
will always return 2
.
With the second example using ?
we are saying that it is OK if the property is not defined at all. Technically both examples mean accessing the address
property on the object john
will evaluate to undefined
, but in the second example Object.keys(john).length
is now 1
. Each version communicates to other developers in your project the way you expect this interface to be used, either the address
property should be explicitly set, or it doesn’t matter if it is set or not.
Which brings us to number 5 in our list of common TypeScript issues: optional property declarations should not use both `?` and `undefined` syntax.
Try the following code in your editor with SonarLint:
Perhaps this happens when you first write the union type of string | undefined
and then you find that TypeScript complains that you aren’t explicitly setting the property everywhere. So you add the optional property syntax to it and the compilation errors go away.
However, now your type gives no indication of how it should be used. The optional syntax means that you don’t need to provide the property explicitly, but the union type suggests that you should. As discussed above, using either option communicates your intention to other developers in the project, but using both communicates nothing and is ultimately confusing. This lint rule ensures that you pick one or the other and avoid confusion:
If you want to avoid getting caught by this TypeScript issue you can default to using the optional property syntax and use the union type with caution. If you have SonarLint installed in your editor then you won’t make this mistake because you will be alerted as it happens.
What’s coming next?
Optional property declarations place fifth in our list of the top 5 most common TypeScript issues. Next week we'll reveal fourth place on the list.
Is this a mistake you’ve made before and did you think it would be so common? What do you think will make up the rest of the top 5? Let us know on Twitter at @SonarSource or in the community.