The `never` type and the `void` type
In TypeScript, never
and void
are two special types used to represent function return values, but their semantics and purposes are distinctly different. void
indicates that a function does not return a value, while never
indicates that a function will never return normally. Understanding their differences is crucial for writing type-safe code.
Basic Concept of void
The void
type signifies that a function does not return a value. When the function completes execution, it returns nothing (or more precisely, returns undefined
). This is the default behavior of functions in JavaScript, and TypeScript explicitly annotates this using the void
type. For example:
function logMessage(message: string): void {
console.log(message);
}
Here, the logMessage
function has no return
statement, so its return type is void
. If you attempt to explicitly return a value, TypeScript will raise an error:
function invalidVoidExample(): void {
return "This will cause an error"; // Error: Type 'string' is not assignable to type 'void'
}
Relationship Between void
and undefined
In TypeScript, void
and undefined
may seem similar but have subtle differences. void
means "no return value," while undefined
is a concrete value. If a function explicitly returns undefined
, its type can be either void
or undefined
:
function returnsUndefined(): undefined {
return undefined; // Valid
}
function alsoReturnsUndefined(): void {
return undefined; // Also valid, because void allows returning undefined
}
But the reverse is not true:
function invalidUndefinedExample(): undefined {
// Error: A function whose declared type is neither 'void' nor 'any' must return a value
}
Basic Concept of never
The never
type indicates that a function will never return normally. It is typically used in the following scenarios:
- Functions that always throw an exception.
- Functions containing infinite loops.
- Branches that should never exist after type narrowing.
Functions That Throw Exceptions
If a function always throws an error, it never has a chance to return a value, so its return type is never
:
function throwError(message: string): never {
throw new Error(message);
}
Functions with Infinite Loops
Similarly, if a function contains an infinite loop, its return type is also never
:
function infiniteLoop(): never {
while (true) {
// Infinite execution
}
}
never
in Type Narrowing
In type guards or conditional types, never
can represent branches that should never exist. For example:
type NonString<T> = T extends string ? never : T;
function filterStrings<T>(value: T): NonString<T> {
if (typeof value === "string") {
throw new Error("Strings are not allowed");
}
return value; // Type is NonString<T>
}
Key Differences Between void
and never
-
Semantic Difference
void
: The function completes execution normally but returns no value.never
: The function cannot complete execution normally.
-
Assignability
void
can be assigned toundefined
ornull
(whenstrictNullChecks
is off).never
is a subtype of all types and can be assigned to any type, but no type can be assigned tonever
(exceptnever
itself).
let v: void = undefined; // Valid
let n: never = throwError("error"); // Only assignable via a never-returning function
// The following will raise an error
let invalidNever: never = 42; // Error: Type 'number' is not assignable to type 'never'
- Behavior in Union Types
void
is preserved in union types.never
is ignored in union types because it represents "impossible to exist."
type UnionWithVoid = string | void; // string | void
type UnionWithNever = string | never; // string
Practical Use Cases
Typical Uses of void
- Event Handlers
Many event handlers do not return a value, makingvoid
suitable:
button.addEventListener("click", (): void => {
console.log("Button clicked");
});
- Side Effects in React Components
In React, if a component method is only used for side effects, it can be declared asvoid
:
class MyComponent extends React.Component {
handleClick(): void {
this.setState({ clicked: true });
}
}
Typical Uses of never
- Exhaustiveness Checking
Inswitch
orif-else
chains,never
ensures all possible cases are handled:
type Shape = "circle" | "square" | "triangle";
function getArea(shape: Shape): number {
switch (shape) {
case "circle":
return Math.PI * 2;
case "square":
return 4;
case "triangle":
return 3;
default:
const exhaustiveCheck: never = shape; // If Shape adds new types, this will error
throw new Error(`Unknown shape: ${exhaustiveCheck}`);
}
}
- Higher-Order Type Utilities
In conditional types,never
is often used to filter or combine types:
type ExtractStrings<T> = T extends string ? T : never;
type Result = ExtractStrings<"a" | 1 | true>; // "a"
Common Pitfalls and Misconceptions
-
Confusing
void
andundefined
Althoughvoid
allows returningundefined
, they are different concepts.void
is a type annotation, whileundefined
is a value. -
Misusing
never
as a Variable Type
Declaring a variable of typenever
is usually meaningless because it cannot be assigned (except via anever
-returning function):
let x: never; // Cannot be assigned
x = 42; // Error
- Ignoring
never
in Type Narrowing
In complex type logic, failing to usenever
properly can lead to type safety issues. For example:
function badTypeGuard(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase();
}
if (typeof value === "number") {
return value.toFixed(2);
}
// Here, value is of type never, but if unhandled, it may hide bugs
}
Interactions in Advanced Type Systems
Behavior of void
in Generics
When void
is used as a generic parameter, it is treated as a regular type:
type Wrapper<T> = { value: T };
const wrappedVoid: Wrapper<void> = { value: undefined }; // Valid
never
and Conditional Types
In conditional types, never
triggers distributive behavior:
type Distributed<T> = T extends any ? T[] : never;
type Result = Distributed<"a" | never>; // "a"[]
Function Type Compatibility
void
return types have special rules in function compatibility. When a function type is declared as void
, the actual implementation can return any value (though the value will be ignored):
type VoidFunc = () => void;
const fn: VoidFunc = () => "hello"; // No error, but the return value is ignored
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:模板字面量类型