TypeScript 中的对象可能为“null”错误

当我们尝试访问可能具有 null 值的对象的属性时,会出现错误“Object is possibly ‘null’”。 要解决该错误,如果引用等于 null,请使用可选链接运算符进行短路,例如 emp?.address?.country。

下面是错误如何发生的示例。

type Employee = {
  address: {
    country: string;
    city: string;
  } | null; // 👈️ could be null
};

const emp: Employee = {
  address: null,
};

// ⛔️ Error: Object is possibly 'null'.ts(2531)
console.log(emp.address.country);

Employee 类型的地址属性可能为 null,这会导致错误。

我们可以使用可选的链接 ?. 运算符来解决这个问题。

type Employee = {
  address: {
    country: string;
    city: string;
  } | null;
};

const emp: Employee = {
  address: null,
};

// ✅ No errors
console.log(emp?.address?.country); // 👈️ using optional chaining

问号点 ?. 语法在 TypeScript 中称为可选链接。

这就像使用点表示法访问对象的嵌套属性,但如果引用为空(null 或未定义),它不会导致错误,而是短路返回未定义。

另一种方法是使用一个简单的 if 语句作为类型保护。

type Employee = {
  address: {
    country: string;
    city: string;
  } | null;
};

const emp: Employee = {
  address: null,
};

// 👇️ check if not null or undefined
if (emp.address != null) {
  console.log(emp.address.country);
  console.log(emp.address.city);
}

我们使用 if 语句来检查 emp.address 属性是否不等于 null 或 undefined。

松散比较涵盖 null 和 undefined,因为在松散比较中,null 等于 undefined。

console.log(null == undefined); // 👉️ true
console.log(null === undefined); // 👉️ false

如果我们确定属性不能具有 null 值,我们也可以使用非 null 断言运算符。

type Employee = {
  address: {
    country: string;
    city: string;
  } | null;
};

const emp: Employee = {
  address: {
    country: 'Germany',
    city: 'Hamburg',
  },
};

console.log(emp.address!.country); // 👉️ "Germany"

感叹号是 TypeScript 中的非空断言运算符。

当你使用这种方法时,你基本上告诉 TypeScript 这个值永远不会是 null 或 undefined。

我们在 address 属性之后使用它,所以我们告诉 TypeScript emp.address 永远不会有 null 或 undefined 的值。

如果在 if 语句中进行比较,请使用逻辑 AND (&&) 运算符来确保属性的类型正确。

type Employee = {
  address: {
    country: string;
    city: string;
    num?: number;
  } | null;
};

const emp: Employee = {
  address: null,
};

if (
  emp.address &&
  typeof emp.address.num === 'number' &&
  emp.address.num > 50
) {
  console.log('success');
}

逻辑 AND && 运算符确保地址属性不为空,num 存在于地址对象中并且是一个数字,然后再将其与数字 50 进行比较。

例如,这会失败:

type Employee = {
  address: {
    country: string;
    city: string;
    num?: number;
  } | null;
};

const emp: Employee = {
  address: null,
};

// ⛔️ could be undefined, so not allowed
if (emp?.address?.num > 50) {
  console.log('success');
}

结果可能具有未定义的值,因为这是可选链接 ?. 运算符短路时的返回值。 TypeScript 不允许我们将可能未定义的值与数字进行比较。

避免出现错误的另一种常见方法是在访问属性时使用逻辑与 (&&) 运算符。

type Employee = {
  address: {
    country: string;
    city: string;
  } | null;
};

const emp: Employee = {
  address: null,
};

if (emp.address && emp.address.country) {
  // 👉️ emp.address.country is type string here
  console.log(emp.address.country.toUpperCase());
}

if 条件中的所有值都必须为真,if 块才能运行。

真值是所有非假值。

JavaScript 中的假值是:undefined、null、false、0、””(空字符串)、NaN(不是数字)。

在这种情况下,解决“对象可能为空”错误的更好方法是使用 typeof 运算符。

type Employee = {
  address: {
    country: string;
    city: string;
  } | null;
};

const emp: Employee = {
  address: null,
};

if (emp.address && typeof emp.address.country === 'string') {
  // 👉️ emp.address.country is type string here
  console.log(emp.address.country.toUpperCase());
}

我们明确检查 country 属性的类型是否为字符串。 这比检查值是否为真要好,因为空字符串在 JavaScript(和 TypeScript)中是假值。

这是一个示例,说明为什么使用 typeof 更好。

type Employee = {
  address: {
    country: string;
    city: string;
  } | null;
};

const emp: Employee = {
  address: {
    country: '',
    city: '',
  },
};

if (emp.address && emp.address.country) {
  const result = emp.address.country;
  console.log(result);
} else {
  // 👉️ else block runs
  console.log('✅ This block runs');
}

else 块在示例中运行。

尽可能明确并使用 typeof 运算符总是更好。 这有助于我们避免一些难以发现的错误。

总结

当我们尝试访问可能具有 null 值的对象的属性时,会发生“ Object is possibly ‘null’ ” 错误。 要解决该错误,请使用可选的链接运算符或类型保护来确保在访问属性之前引用不为空。