Announcing: A Free Book, A New Course, A Huge Price Cut...
It's a massive ship day. We're launching a free TypeScript book, new course, giveaway, price cut, and sale.
as never
is very occasionally needed in TypeScript. Let's look at an example where it's necessary.
Let's imagine we want to format some input based on its typeof
. We first create a formatters
object that maps typeof
to a formatting function:
const formatters = {
string : (input : string) => input .toUpperCase (),
number : (input : number) => input .toFixed (2),
boolean : (input : boolean) => (input ? "true" : "false"),
};
Next, we create a format
function that takes an input of string | number | boolean
and formats it based on its typeof
.
const format = (input : string | number | boolean) => {
// We need to cast here because TypeScript isn't quite smart
// enough to know that `typeof input` can only be
// 'string' | 'number' | 'boolean'
const inputType = typeof input as
| "string"
| "number"
| "boolean";
const formatter = formatters [inputType ];
return formatter (input );Argument of type 'string | number | boolean' is not assignable to parameter of type 'never'.
Type 'string' is not assignable to type 'never'.2345Argument of type 'string | number | boolean' is not assignable to parameter of type 'never'.
Type 'string' is not assignable to type 'never'.};
But there's a strange error:
Type 'string' is not assignable to type 'never'.
What's going on here?
Let's take a deeper look at the type of formatter
inside our format
function:
const format = (input : string | number | boolean) => {
const inputType = typeof input as
| "string"
| "number"
| "boolean";
const formatter = formatters [inputType ];
return formatter (input );
};
As you can see, it resolves to a union of functions, each with a different parameter. One function takes a string
, another a number
, and the last a boolean
.
How could we possibly call this function with a string
and a number
at the same time? We can't.
So, the function actually resolves to:
type Func = (input : never) => string;
You might be thinking, "Shouldn't the parameters resolve to a union of string | number | boolean
?"
This doesn't work, because calling formatters.string
with a number
is unsafe. Calling formatters.boolean
with a number
is unsafe.
So, never
is the only type that makes sense.
We happen to know that the logic of this function is sound. We know that formatters[inputType]
will resolve to the correct type.
So, we can use an as never
:
const format = (input : string | number | boolean) => {
const inputType = typeof input as
| "string"
| "number"
| "boolean";
const formatter = formatters [inputType ];
return formatter (input as never);
};
This forces TypeScript to consider input
as the type of never
- which is, of course, assignable to formatter
's parameter of never
.
as any
Work?Amazingly, any
doesn't work here:
const format = (input : string | number | boolean) => {
const inputType = typeof input as
| "string"
| "number"
| "boolean";
const formatter = formatters [inputType ];
return formatter (input as any );Argument of type 'any' is not assignable to parameter of type 'never'.2345Argument of type 'any' is not assignable to parameter of type 'never'.};
It results in a horrendous error:
Argument of type 'any' is not assignable to parameter of type 'never'.
So, as never
is the only way to go here.
Share this article with your friends
It's a massive ship day. We're launching a free TypeScript book, new course, giveaway, price cut, and sale.
Learn why the order you specify object properties in TypeScript matters and how it can affect type inference in your functions.
Learn how to use corepack
to configure package managers in Node.js projects, ensuring you always use the correct one.
Learn how to strongly type process.env in TypeScript by either augmenting global type or validating it at runtime with t3-env.
Discover when it's appropriate to use TypeScript's any
type despite its risks. Learn about legitimate cases where any
is necessary.
Learn why TypeScript's types don't exist at runtime. Discover how TypeScript compiles down to JavaScript and how it differs from other strongly-typed languages.