With Typescript, you can do strict type checking at compile time or before, thanks to Typescript's features and help from IDE.
Let us say we want to define an object having properties of smartphones. We can achieve it like the code below:
const SMARTPHONE_MAPPING = {
IPHONE_12 : {displaySize: 6.06, weight: "164g"},
GALAXY_S22: {displaySize: 6.1, weight: "168g"},
};
Of course, there are numerous phones out there,
so we might add more phones later on. Also,
we do not know what names those phone will be called,
so SMARTPHONE_MAPPING
would have arbitrary random keys.
But while adding more phones, we do not want to introduce any errors, such as usual developer errors like below:
const SMARTPHONE_MAPPING = {
IPHONE_12 : {displaySize: 6.06, weight: "164g"},
GALAXY_S22: {displaySize: 6.1, weight: "168g"},
IPHONE_13 : {dispaylSize: 7, weight: "150g"}, // key typo
GALAXY_S23: {displaySize: 7, }, // missing key
};
What we want inside SMARTPHONE_MAPPING
are nothing but
display size and weight properties only.
How do we ensure that the values in the object are of the type?
Well, we can give a type to the object, like below:
type SMARTPHONE_MAP_TYPE = {[key: string]: {displaySize: number, weight: string}}
// Or we can defind the type as Record.
// type SMARTPHONE_MAP_TYPE = Record<string, {displaySize: number, weight: string}}>
const SMARTPHONE_MAPPING: SMARTPHONE_MAP_TYPE = {
IPHONE_12 : {displaySize: 6.06, weight: "164g"},
GALAXY_S22: {displaySize: 6.1, weight: "168g"},
};
But the problem of giving the object a type is that IDE now does not show us the autocomplete of the member keys.
Before Having explicit type
After Having explicit type
Well, why does this happen?
This is because the type of the variable is SMARTPHONE_MAP_TYPE
,
where there is no information about what is in the object.
All the information about what's inside the variable
has been deprecated. All it knows about the keys is that
they are string type. Please take a look at the type hints
and find out what are the differences.
Before Having explicit type
After Having explicit type
SMARTPHONE_MAP_TYPE
does not contain any information about
what are members but only that the keys are in string,
and the values are in object containing the two properties.
SMARTPHONE_MAPPING
does know the member keys, but
giving the explicit type to the object made it
blind about what is inside the object.
Solution
To solve this, we can implement a generic function
which accepts arg
which extends SMARTPHONE_MAP_TYPE
,
and returns arg
as is. See asType
function below:
type SMARTPHONE_MAP_TYPE = {[key: string]: {displaySize: number, weight: string}}
function asType<T extends SMARTPHONE_MAP_TYPE>(arg: T): T{
return arg;
}
const SMARTPHONE_MAPPING = asType({
IPHONE_12 : {displaySize: 6.06, weight: "164g"},
GALAXY_S22: {displaySize: 6.1, weight: "168g"},
});
Since the function returns T
type which extends SMARTPHONE_MAP_TYPE
,
we can have strict type checking.
And since the function returns arg
which is of T
type,
not SMARTPHONE_MAP_TYPE
, the returned value has information what is inside itself.
Now we have both strict type checking and autocompletion. :)
However, this solution is a little bit tedious with runtime overhead due to asType
function calls.
Luckily, Typescript is going to introduce satisfies
keyword
in the near future, maybe in 4.7
version.
⚠️ 09/04/2022 Update
satisfies
keyword PR finally got merged in main brnach (PR link) and is expected to be released in4.9
version. Check their iteration plan for more information.
type SMARTPHONE_MAP_TYPE = {[key: string]: {displaySize: number, weight: string}}
const SMARTPHONE_MAPPING = {
IPHONE_12 : {displaySize: 6.06, weight: "164g"},
GALAXY_S22: {displaySize: 6.1, weight: "168g"},
} satisfies SMARTPHONE_MAP_TYPE;
Check out the related Github issue on Typescript repository for more. [Link]