never 类型是 TypeScript 中的底层类型,表示永远不会发生的值的类型。它在类型系统中有着许多精妙的用途,让我们一起来探索:
never 类型表示:
// 永远不会返回的函数
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
这是 never 最强大的用途之一,确保处理所有可能的情况:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; size: number }
| { kind: "triangle"; base: number; height: number };
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.size ** 2;
case "triangle":
return 0.5 * shape.base * shape.height;
default:
// 如果添加了新 shape 但忘记处理,这里会报错
const _exhaustiveCheck: never = shape;
throw new Error(`Unknown shape: ${_exhaustiveCheck}`);
}
}
// 新增 shape 但忘记处理时:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; size: number }
| { kind: "triangle"; base: number; height: number }
| { kind: "hexagon"; side: number }; // 新增
// 此时 getArea 会报错:
// 类型“{ kind: "hexagon"; side: number; }”的参数不能赋给类型“never”
结合条件类型过滤联合类型:
// 过滤掉 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;
type Example = NonNullable<string | number | null | undefined>;
// 结果:string | number
// 从对象类型中移除某些属性
type RemoveField<T, K extends keyof T> = {
[P in keyof T as P extends K ? never : P]: T[P]
};
type User = { id: number; name: string; age: number };
type WithoutAge = RemoveField<User, 'age'>;
// 结果:{ id: number; name: string }
// 用于状态机,表示不可能的状态
type LoadingState = { status: 'loading' };
type SuccessState<T> = { status: 'success'; data: T };
type ErrorState = { status: 'error'; error: Error };
type ApiState<T> = LoadingState | SuccessState<T> | ErrorState;
function handleState<T>(state: ApiState<T>): void {
switch (state.status) {
case 'loading':
console.log('Loading...');
break;
case 'success':
console.log('Data:', state.data);
break;
case 'error':
console.log('Error:', state.error);
break;
default:
const _: never = state;
console.log('Impossible state:', _);
}
}
// 类型安全的空对象
type EmptyObject = { [K in any]: never };
const empty: EmptyObject = {}; // ✅
const notEmpty: EmptyObject = { a: 1 }; // ❌ 报错
// 禁止额外属性的类型
type Exact<T, U extends T> = T & Record<Exclude<keyof U, keyof T>, never>;
type UserConfig = { name: string; age: number };
type StrictConfig = Exact<UserConfig, UserConfig>;
const config: StrictConfig = {
name: "John",
age: 30,
extra: "prop" // ❌ 报错:额外属性不允许
};
// 确保函数不会被调用
type NeverFunction = (...args: never[]) => any;
// 实用案例:防止调用特定函数
type DeprecatedMethod = (...args: never[]) => void;
class API {
// 旧方法标记为废弃
oldMethod: DeprecatedMethod = () => {
throw new Error('This method is deprecated');
};
newMethod() {
console.log('Use this instead');
}
}
const api = new API();
api.oldMethod(); // ❌ 编译时错误:不能调用 never[] 参数的函数
type Action =
| { type: 'INCREMENT'; payload: number }
| { type: 'DECREMENT'; payload: number }
| { type: 'RESET' };
type ActionTypes = Action['type']; // "INCREMENT" | "DECREMENT" | "RESET"
type Handlers<State, Actions> = {
[K in ActionTypes]: (
state: State,
action: Extract<Actions, { type: K }>
) => State
};
const reducer = <State>(
initialState: State,
handlers: Handlers<State, Action>
) => {
return (state = initialState, action: Action): State => {
const handler = handlers[action.type as keyof typeof handlers];
if (handler) {
return handler(state, action as any);
}
// 如果没有匹配的处理函数,应该是一个错误
const _: never = action;
return state;
};
};
const counterReducer = reducer(
0,
{
INCREMENT: (state, action) => state + action.payload,
DECREMENT: (state, action) => state - action.payload,
RESET: () => 0,
}
);
type Pattern<T, R> = {
[K in keyof T]?: (value: T[K]) => R
} & {
_?: () => R
};
class Matcher<T extends Record<string, any>, R> {
constructor(private value: T) {}
with(pattern: Pattern<T, R>): R {
for (const key in this.value) {
const handler = pattern[key as keyof typeof pattern];
if (handler) {
return handler(this.value[key]);
}
}
if (pattern._) {
return pattern._();
}
const _: never = this.value;
throw new Error(`No pattern matched: ${JSON.stringify(_)}`);
}
}
const result = new Matcher({ type: 'success', data: 'hello' }).with({
success: (data) => `Data: ${data}`,
error: (err) => `Error: ${err}`,
_: () => 'Unknown'
});
type ApiResponse<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: string };
function handleResponse<T>(response: ApiResponse<T>) {
switch (response.status) {
case 'idle':
return 'Ready to fetch';
case 'loading':
return 'Loading...';
case 'success':
return `Data: ${response.data}`;
case 'error':
return `Error: ${response.error}`;
default:
// 确保所有状态都被处理
const _: never = response;
return `Unexpected state: ${_}`;
}
}
// 类型安全的 assertNever 工具函数
function assertNever(x: never): never {
throw new Error(`Unexpected object: ${x}`);
}
// 类型安全的 switch 辅助函数
function match<T extends { type: string }, R>(
value: T,
cases: { [K in T['type']]: (value: Extract<T, { type: K }>) => R }
): R {
const handler = cases[value.type as keyof typeof cases];
if (handler) {
return handler(value as any);
}
return assertNever(value);
}
never 类型的精妙之处在于:
掌握 never 类型的这些用法,能让你的 TypeScript 代码更加健壮、类型安全,并在编译时捕获更多潜在的错误。