Beginner’s TypeScript #22

Nhan Nguyen
4 min readJan 14, 2024

Error Message: “Types Of Property Are Incompatible”

We have a routingConfig object which contains some routes. These routes are an array of objects, each with a path and a component property, both of which are expected to be strings:

const routingConfig = {
routes: [
{
path: "home",
component: "HomeComponent",
},
{
path: "about",
component: "AboutComponent",
},
{
path: "contact",
component: "ContactComponent",
},
],
}

We also have a createRoutes function that takes this routingConfig, and maps it into a type:

const createRoutes = (config: {
routes: {
path: string;
component: string;
}[];
}) => {};

When calling createRoutes with the routingConfig, we get a large error message:

createRoutes(routingConfig); // red squiggly line under routingConfig

// hovering over routingConfig shows:
Argument of type '{ routes: { path: string; component: string | number; }[]; }' is not assignable to parameter of type '{ routes: { path: string; component: string; }[]; }'.
Types of property 'routes' are incompatible.
Type '{ path: string; component: string | number; }[]' is not assignable to type '{ path: string; component: string; }[]'.
Type '{ path: string; component: string | number; }' is not assignable to type '{ path: string; component: string; }'.
Types of property 'component' are incompatible.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.

We will figure out what this error is telling us, and make the error more readable.

We have a large error message that was difficult to understand:

Argument of type '{ routes: { path: string; component: string | number; }[]; }' is not assignable to parameter of type '{ routes: { path: string; component: string; }[]; }'.
Types of property 'routes' are incompatible.
Type '{ path: string; component: string | number; }[]' is not assignable to type '{ path: string; component: string; }[]'.
Type '{ path: string; component: string | number; }' is not assignable to type '{ path: string; component: string; }'.
Types of property 'component' are incompatible.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.

The first line tells us that when we pass the routingConfig object into the createRoutes function, the shape of the object is not compatible with the shape of the parameter.

Next, we see that the routes are incompatible.

Continuing on, we can see that a union of string | number is trying to be assigned to just string.

Finally, we see that number is not assignable to string.

Usually, when faced with a large error message like this, it is a good idea to start from the bottom.

Since we have a number being passed into a slot that expects a string, we can scan upwards to identify the property that is causing the issue. In this case, it is the component property.

Inside of the routes array, the about path’s component property is 12 instead of a string:

const routingConfig = {
routes: [
{
path: "home",
component: "HomeComponent",
},
{
path: "about",
component: 12, // Error occurs here
},
{
path: "contact",
component: "ContactComponent",
},
],
}

Now, we know what is causing the error and even have some ideas about how to fix it, but we still need to clean up the error message.

👉 Solution

There are a few ways to make the error readable and informative:

1️⃣ Pass the Object Inline

One way to make the error message better is instead of declaring routingConfig as a separate object, pass it inline:

createRoutes({
routes: [
{
path: "home",
component: "HomeComponent",
},
{
path: "about",
component: 12, // Error occurs here
},
{
path: "contact",
component: "ContactComponent",
},
],
})

This lets TypeScript make better assumptions about the object, resulting in a more relevant error message.

Hovering over **createRoutes **shows us the shape:

const createRoutes: (config: {
routes: {
path: string;
component: string;
}[];
}) => void;

Now there will be an error underlining the component where the error occurs:

...
{
path: "about",
component: 12, // red squiggly line under component
},
...

Hovering over component to see the error message, it is more clear:

Type 'number' is not assignable to type 'string'.
The expected type comes from property 'component' which is declared here on type '{ path: string; component: string; }'

Having the separate routingConfig object does not give us nice error messages because TypeScript is not sure if we will be using it in a different scenario elsewhere in the code.

2️⃣ Use Type Annotations

Assigning explicit type annotations to the objects also will help TypeScript deliver a more concrete error message.

First, create a new RoutingConfig type, then use it as the config type for the createRoutes function:

type RoutingConfig = {
routes: {
path: string;
component: string;
}[];
};

const createRoutes = (config: RoutingConfig) => {};

Then we can also annotate the routingConfig object:

const routingConfig: RoutingConfig = {
routes: [
{
path: "home",
component: "HomeComponent",
},
{
path: "about",
component: "AboutComponent",
},
{
path: "contact",
component: "ContactComponent",
},
],
}

Again, this will give us a more relevant error message inside of routingConfig.

3️⃣ Use the satisfies Keyword

Finally, we could use the satifies keyword on the routingConfig object to specify it as a RoutingConfig type:

const routingConfig: RoutingConfig = {
routes: [
{
path: "home",
component: "HomeComponent",
},
{
path: "about",
component: 12, // red squiggly line under component
},
{
path: "contact",
component: "ContactComponent",
},
],
} satisfies RoutingConfig;

All of these strategies are great for getting TypeScript to provide more useful error messages.

I hope you found it useful. Thanks for reading. 🙏

Let’s get connected! You can find me on:

--

--