Published on

TypeScript Error: Type string | undefined is not assignable to type string

Resolving Typescript's TS2322 on wrong assignments

Note: TS2322: Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'.

Table of Contents

Problem Description:

The error message TS2322 indicates that there is a type mismatch in the assignment of a variable. A potential problem arises when we try to assign a variable with a 'narrow' type to a Union Type variable, and we should be careful to avoid this pitfall in TypeScript.

In this case, the type of the variable is string | undefined, which means that it can either be a string or undefined. However, the type of the variable being assigned to, it requires a strict string type, meaning it must be a string and cannot be undefined.

Example case:

The example below its showcasing a type mismatch while we are trying to set colorDisplayName which is of type string and the name is a superset which also could be undefined.

ts2223.tsx
interface Color {
  name?: string
  hex: string
  rgb: string
}

const myColor: Color = {
  name: 'rgb(0, 191, 255)',
  hex: '#00bfff',
  rgb: 'rgb(0, 191, 255)',
}

const colorDisplayName: string = myColor.name //🚫 ERROR ts(2223)

Solutions:

There are several ways to resolve this error, depending on the context and requirements of our code.

In order to tackle such cases we either need both variables to have all exact same types as a match; or we can omit a type in some cases; like for example when we have undefined as a secondary type.

Here are some possible solutions:

1.Type guarding the variable

A type guard is a way to check the type of variable before using it in our code. In this case, we can use a type guard to check if the variable is being defined before assigning it to a string colorDisplayName.

ts2223.tsx
interface Color {
  name?: string
  hex: string
  rgb: string
}

const myColor: Color = {
  name: 'rgb(0, 191, 255)',
  hex: '#00bfff',
  rgb: 'rgb(0, 191, 255)',
}

if (myColor.name !== undefined) {
  const colorDisplayName: string = myColor.name
}

2.Non-null assertion operator 'variable!'

The Non-null assertion operator is a post-fix operator that can assert that our variable is non null, and we can access name. If we are confident the variable will never be undefined, we can use a non-null assertion operator to force TypeScript to treat the variable as a non-null value.

ts2223.tsx
interface Color {
  name?: string
  hex: string
  rgb: string
}

const myColor: Color = {
  name: 'rgb(0, 191, 255)',
  hex: '#00bfff',
  rgb: 'rgb(0, 191, 255)',
}

const colorDisplayName: string = myColor.name!

Warning: This solution would be preferred when we are sure the incoming variable will always be populated.

3.Type Assertion 'variable as sometype'

The Type assertions basically is been used to instruct Typescript at compile-time the exact type to be used. And in our example is no diferent than the Non-null operator where we are forcing the type we want by omitting the case that the variable can be undefined.

ts2223.tsx
interface Color {
  name?: string
  hex: string
  rgb: string
}

const myColor: Color = {
  name: 'rgb(0, 191, 255)',
  hex: '#00bfff',
  rgb: 'rgb(0, 191, 255)',
}

const colorDisplayName: string = myColor.name as string

4a.Default Value: with the Logical OR operator '||'

With the Logical OR we can act in the similar way with the Nullish coalescing operator by in this case we cover more scenarios and not only null or undefined, but also empty '' ,false ,0, and NaN

ts2223.tsx
interface Color {
  name?: string
  hex: string
  rgb: string
}

const myColor: Color = {
  name: 'rgb(0, 191, 255)',
  hex: '#00bfff',
  rgb: 'rgb(0, 191, 255)',
}

const colorDisplayName: string = myColor.name || ''

4b.Default Value: with the Nullish coalescing '??'

We can use nullish coalescing as a fallback mechanism when our variable is null or undefined, then we can set some default value, so it will comply the string only restriction.

ts2223.tsx
interface Color {
  name?: string
  hex: string
  rgb: string
}

const myColor: Color = {
  name: 'rgb(0, 191, 255)',
  hex: '#00bfff',
  rgb: 'rgb(0, 191, 255)',
}

const colorDisplayName: string = myColor.name ?? ''

4c.Default Value: with The Ternary operator 'condition ? exprIfTrue : exprIfFalse'

With the Ternary operator we can type guard and assert the possibility of placing an undefined value into out variable colorDisplayName

ts2223.tsx
interface Color {
  name?: string
  hex: string
  rgb: string
}

const myColor: Color = {
  name: 'rgb(0, 191, 255)',
  hex: '#00bfff',
  rgb: 'rgb(0, 191, 255)',
}

const colorDisplayName: string = myColor.name ? myColor.name : ''

Warning: Using default value to tackle that issue might not be always the preferred choice.

Summary:

we can resolve TS2322 with:

  • Type guard
  • Non-null Assertion
  • Type Assertion
  • Default Value