Insufficient overlaps with types - Convert to unknown first

What does this error mean? How do I know what types overlap in TypeScript? How does unknown solve the problem here?

Here’s one way this error can be triggered:

let variable = "string";

let value = /**/variable as number/**/
Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first

Here, we have variable typed to be string. Then we attempt to do a Type Assertion as for variable to be of a number type for data. But then, TypeScript sees this as “not possible”. A string type cannot be converted to a number type directly because number doesn’t overlap with string.

If you’re wondering what an overlap is in this case, let me show you:

let variable: 3 | 4 | 5 = 3

let value = variable as number
// value = 20

Here, we typed variable to be a union of 3, 4 and 5. In the next line, we cast variable as number and now things work fine. That’s because there’s an overlap between 3, 4, 5 and number which is the fact that they are all numbers.

Another example:

function print(param: string | number) {
  const data = param as number
}

param as number has an overlap with the fact that param is typed string or number.

So back to the original problem:

let variable = "string";

let value = /**/variable as number/**/
Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first

What if you actually want to cast variable as number regardless? In the example above, it might not make sense to do that but let me show you one case where it might make sense:

const pathname = getPathname()
const prefixPathname =
  /**/pathname.match(/\/[^\/]+/) as string/**/
Conversion of type 'RegExpMatchArray | null' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first...Type 'RegExpMatchArray' is not comparable to type 'string'

This is from the code of this website. You can see the code here. What I’m trying to get here is the prefix path. For example, pathname of /about/the-company, the prefix path will be /about. I needed this so that I could style the header navigation links.

From the error, what we see is that pathname.match(...) returns a type of RegExpMatchArray | null. But I’m trying to cast this return type as string. Obviously, string doesn’t overlap. But in this case, I can say “I am sure this will return a string” because the regex match which actually returns an array (if there are matches), will be coerced to a string when I use it in a string expression; just like I did here.

In this case, how can I successfully do the type assertion? Well as the TypeScript error hints: “convert the expression to unknown first”. unknown overlaps with any type. As the doc says:

Anything is assignable to unknown

So we can cast RegExpMatchArray | null to unknown, then we can cast unknown to string:

const pathname = getPathname()
const prefixPathname =
  pathname.match(/\\/[^\\/]+/)
    as unknown as string

And now, everything works fine. Because string also overlaps with unknown. For our first example, we can do the same thing:

let variable = "string";

let value = variable as unknown as number

unknown overlaps with string, and number overlaps with unknown.