欢迎光临中国葬花网
详情描述

never 类型是 TypeScript 中的底层类型,表示永远不会发生的值的类型。它在类型系统中有着许多精妙的用途,让我们一起来探索:

1. 基础概念

never 类型表示:

  • 永远不会返回的函数(如抛出错误或无限循环)
  • 永远不可能为真的条件分支
  • 不可能存在的情况
// 永远不会返回的函数
function throwError(message: string): never {
    throw new Error(message);
}

function infiniteLoop(): never {
    while (true) {}
}

2. 精妙用法详解

2.1 穷尽性检查(Exhaustiveness Checking)

这是 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”

2.2 过滤不可能的类型

结合条件类型过滤联合类型:

// 过滤掉 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 }

2.3 表示不可能的状态

// 用于状态机,表示不可能的状态
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:', _);
    }
}

2.4 实现精确的类型操作

// 类型安全的空对象
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" // ❌ 报错:额外属性不允许
};

2.5 函数参数约束

// 确保函数不会被调用
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[] 参数的函数

3. 高级模式

3.1 类型安全的 Redux Reducer

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,
    }
);

3.2 模式匹配器

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'
});

4. 实际应用场景

4.1 API 响应处理

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: ${_}`;
    }
}

4.2 构建类型安全的工具

// 类型安全的 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 类型的精妙之处在于:

类型安全性:通过穷尽性检查确保所有情况都被处理 类型操作:在条件类型中过滤和转换类型 设计模式:实现不可达代码的编译时检查 状态管理:构建类型安全的状态机和模式匹配器 API 设计:创建不可能被误用的接口

掌握 never 类型的这些用法,能让你的 TypeScript 代码更加健壮、类型安全,并在编译时捕获更多潜在的错误。

相关帖子
预防工资被拖,入职时和在职期间可以提前做好的关键准备有哪些?
预防工资被拖,入职时和在职期间可以提前做好的关键准备有哪些?
不同城市垃圾分类标准的主要差异体现在哪里?
不同城市垃圾分类标准的主要差异体现在哪里?
国际上其他地区缩小城乡收入差距的经验,有哪些可供我们借鉴?
国际上其他地区缩小城乡收入差距的经验,有哪些可供我们借鉴?
应对国际市场波动,2026年我国谷子产业的风险管理与保险策略
应对国际市场波动,2026年我国谷子产业的风险管理与保险策略
未来五年,社区环保与公共文明将会有哪些新趋势?
未来五年,社区环保与公共文明将会有哪些新趋势?
在异地提交了换证申请后,因故需要取消或修改信息该如何操作?
在异地提交了换证申请后,因故需要取消或修改信息该如何操作?
山南市网站优化公司#精准获客助手,模板建站
山南市网站优化公司#精准获客助手,模板建站
农业遥感如何帮助农民了解作物长势并预估产量,2026年有哪些新应用?
农业遥感如何帮助农民了解作物长势并预估产量,2026年有哪些新应用?
在选择医保定点药店时,我们应该重点考虑和对比哪些因素?
在选择医保定点药店时,我们应该重点考虑和对比哪些因素?
为什么说智能水表和电表的数据,正在成为评估个人信用的潜在依据?
为什么说智能水表和电表的数据,正在成为评估个人信用的潜在依据?
南充市安卓系统app开发@品牌网站定制开发,专业建站
南充市安卓系统app开发@品牌网站定制开发,专业建站
恋爱期间共同出资买房但未结婚,房产的归属问题应该如何妥善处理?
恋爱期间共同出资买房但未结婚,房产的归属问题应该如何妥善处理?
如果未来想买下政府持有的产权份额,具体的评估和购买流程是怎样的?
如果未来想买下政府持有的产权份额,具体的评估和购买流程是怎样的?
在2026年,面对越来越逼真的AI生成内容,我们该如何保持警惕?
在2026年,面对越来越逼真的AI生成内容,我们该如何保持警惕?
员工主动辞职时,当年未休的年休假工资应该如何正确计算和支付?
员工主动辞职时,当年未休的年休假工资应该如何正确计算和支付?
2026年想将家里的高额宽带套餐降级,运营商却设置重重障碍该怎么办?
2026年想将家里的高额宽带套餐降级,运营商却设置重重障碍该怎么办?
汉中市正规殡葬公司|丧葬服务公司,搭设灵堂
汉中市正规殡葬公司|丧葬服务公司,搭设灵堂
在停工停课期间,企业是否有权安排员工使用带薪年假或其他假期?
在停工停课期间,企业是否有权安排员工使用带薪年假或其他假期?
延安市网站建设推广服务#外贸网站建设,高端网站开发设计
延安市网站建设推广服务#外贸网站建设,高端网站开发设计
如果用人单位拒绝发放高温津贴,作为普通员工应该如何有效维权?
如果用人单位拒绝发放高温津贴,作为普通员工应该如何有效维权?