You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何TypeScript已做非空检查仍提示对象可能为undefined?

TypeScript类型收窄失效问题解析

最小可复现示例

type Keys = "FOO" | "BAR";

type ThingType = {
    category: Keys,
    thingName: string;
}

type CategorisedThings = Partial<Record<Keys, string[]>>
type ListedThings = ThingType[]

const categorizeFunction = (listedThings: ListedThings) => {
    const result: CategorisedThings = {}
    for (const thing of listedThings) {
        if (result[thing.category] !== undefined) {             // 第14行
            result[thing.category].push(thing.thingName)       // 第15行
        } else {
            result[thing.category] = [thing.thingName]
        }
    }
}

上述示例中,TypeScript在第15行抛出错误:Object is possibly 'undefined'.

result[thing.category].push(thing.thingName)
            ^^^^^^^^^^^^^^^^^^^^^^

问题原因

TypeScript的类型检查器无法精准追踪result[thing.category]在条件判断和后续访问之间的关联。因为thing.category是"FOO" | "BAR"的联合类型,虽然我们逻辑上清楚两次访问的是同一个属性,但类型系统跨语句时,无法确定thing.category的具体值没有变化——哪怕它在循环里是常量,TypeScript也没法把两次属性访问的类型收窄关联起来。

另外,CategorisedThings的类型是Partial<Record<Keys, string[]>>,这意味着每个键对应的类型都是string[] | undefined,对于联合类型键的属性访问,TypeScript的类型收窄机制无法做到精准识别,所以即便做了undefined检查,它还是会认为属性可能为undefined。

解决方案

1. 用临时变量存储属性值

把要访问的属性值存到临时变量里,TypeScript就能追踪这个变量的类型,自然不会报错:

const categorizeFunction = (listedThings: ListedThings) => {
    const result: CategorisedThings = {}
    for (const thing of listedThings) {
        const categoryItems = result[thing.category];
        if (categoryItems !== undefined) {
            categoryItems.push(thing.thingName);
        } else {
            result[thing.category] = [thing.thingName];
        }
    }
}

2. 类型断言(谨慎使用)

如果能确保逻辑绝对没问题,可以用类型断言明确告诉TypeScript该属性不为undefined:

if (result[thing.category] !== undefined) {
    (result[thing.category] as string[]).push(thing.thingName);
}

3. 提前初始化所有键

一开始就给result的所有Keys键初始化空数组,后续就不需要做undefined检查了:

const categorizeFunction = (listedThings: ListedThings) => {
    const result: CategorisedThings = { FOO: [], BAR: [] };
    for (const thing of listedThings) {
        result[thing.category].push(thing.thingName);
    }
}

内容的提问来源于stack exchange,提问作者tim-mccurrach

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:15:17