While you are learning TypeScript and reading someone else’s code, you find there is the following declaration in a file of a project:
interface User {
id: string;
firstName: string;
middleName?: string;
lastName: string;
}
Why does the middleName
property is followed by a question mark ?:
?
Table of Contents
What does ?:
mean in TypeScript?
Using a question mark followed by a colon (?:
) means a property is optional. That said, a property can either have a value based on the type defined or its value can be undefined
.
Similar to using two types where one type is undefined
Another way to think about using a question mark with a colon (?:) is to define two types to a property where one of them is undefined
. Hence, if we make a small modification to the User
interface, the middleName
property will have a type definition of string | undefined
.
interface User {
id: string;
firstName: string;
middleName: string | undefined;
lastName: string;
}
Difference between ?:
and using two types where one type is undefined
There is one problem with using middleName: string | undefined;
instead of middleName?: string;
. The middleName
property is no longer optional.
Depending on the IDE you use, you can get immediate feedback saying the property is required. For example, try adding the following code, which creates an admin
variable with a type of User
that doesn’t have a middleName
:
interface User {
id: string;
firstName: string;
middleName: string | undefined;
lastName: string;
}
const admin: User = {
id: '92d4549c-ebe1-49b4-b113-26cf00d204bc',
firstName: 'Andres',
lastName: 'Reales'
};
You should notice the IDE displays the following error
Property 'middleName' is missing in type '{ id: string; firstName: string; lastName: string; }' but required in type 'User'.(2741)
right underneath the admin
variable:
Unless the admin
has a middleName
value assigned, the code will not run due to compilation errors. In this case, using the question mark with a colon (?:
) is a better alternative as it will make middleName
property optional. In that way, we can update the type definition back to string
only.
interface User {
id: string;
firstName: string;
middleName?: string;
lastName: string;
}
const admin: User = {
id: '92d4549c-ebe1-49b4-b113-26cf00d204bc',
firstName: 'Andres',
lastName: 'Reales',
};
As you notice, the error disappears and the code will compile.
Using ?:
with undefined
as type definition
It is possible to use ?:
with an undefined
type. If you remember the example where we used string | undefined
type definition for the middleName
, we can add the ?:
and keep the undefined
type.
interface User {
id: string;
firstName: string;
middleName?: string | undefined;
lastName: string;
}
While there are no errors with this interface definition, it is inferred the property value could undefined
without explicitly defining the property type as undefined
. In case the middleName property doesn’t get a value, by default, its value will be undefined
.
interface User {
id: string;
firstName: string;
middleName?: string;
lastName: string;
}
const admin: User = {
id: '92d4549c-ebe1-49b4-b113-26cf00d204bc',
firstName: 'Andres',
lastName: 'Reales',
};
console.log(admin.middleName); // it will log: undefined
Question mark ?:
is not only used with interface
s
In the initial example, we noticed the usage of the question mark with a colon (?:
) when defining the properties of an interface. In a similar way, we can do so this when defining a class
.
class Car {
id: string;
brand: string;
model: string;
year: number;
price?: number;
}
This gives the flexibility to not having the need to provide values to all properties of a class
.
We can also define optional parameters when creating functions in TypeScript.
function buyGift(itemId: string, accountId: string, message?: string) {
const item = getItem(itemId);
pay(item.price, accountId);
if (message) {
sendMessage(message);
}
}
buyGift('item id', 'account id');
Notice how we didn’t need to pass all three arguments to trigger the buyGift
function. Instead, we provided only the necessary arguments.
This is a big benefit in TypeScript when compared to defining functions in JavaScript as all of the parameters in JavaScript are optional, even if the logic inside the function requires them, while in TypeScript you have to explicitly add the question mark ?:
to make parameters optional.
Using strictNullChecks
TypeScript Compiler Option
If you don’t know, you can define TypeScript compiler options inside a tsconfig.json
file. This file might have a structure like this:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true
}
}
Defining compiler options inside the compilerOptions
property of the tsconfig.json
file is a good way to enforce a set of rules in the code.
For instance, we know that by defining an interface with an optional property such as middleName?: string
:
interface User {
id: string;
firstName: string;
middleName?: string;
lastName: string;
}
The possible values of middleName
should be either undefined
or a string value. However, what if I show you I can define the value of null
to the middleName
property like in the next code snippet?
const admin: User = {
id: '92d4549c-ebe1-49b4-b113-26cf00d204bc',
firstName: 'Andres',
lastName: 'Reales',
middleName: null
};
While this is not correct, TypeScript might or not display an error. If you are not getting an error, it is because you don’t have strictNullChecks
compiler option. For the purposes of understanding this concept, go ahead and add strictNullChecks
with a value of true
in the TypeScript compiler options and save the changes made in your tsconfig.json
file.
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"strictNullChecks": true
}
}
If you go back to the code, you should see TypeScript displaying the following error:
Type 'null' is not assignable to type 'string | undefined'.(2322)
index.ts(4, 3): The expected type comes from property 'middleName' which is declared here on type 'User'
(property) User.middleName?: string | undefined
in the property middleName
of the admin
object.
In that way, we prevent potential logic issues from happening during runtime.
Conclusion
In this article, you learned what it means to use the question mark followed by a colon ?:
in TypeScript as well as the difference between using ?:
and using undefined
type without the question mark. Also, you can enable strictNullChecks
compiler option to prevent assigning null
values to a property that is an option, unless null
is one of the type definitions of the property.
Interested in Reading More About TypeScript?
I wrote other TypeScript articles, and I thought you might be interested in reading some of them since you are reading this.
- TypeScript | The Unknown Type Guide
- TypeScript | Organizing and Storing Types and Interfaces
- TypeScript | Double Question Marks (??) – What it Means
- TypeScript | Objects with Unknown Keys and Known Values
- TypeScript | Union Types – Defining Multiple Types
- TypeScript | Declare an Empty Object for a Typed Variable
- TypeScript | Union Types vs Enums
- TypeScript | Convert Enums to Arrays
Did you like this article?
Share your thoughts by replying on Twitter of Become A Better Programmer or to personal my Twitter account.