我正在为一个对象编写一个类型保护。我使用早期返回来保持缩进的可读性,但这个例子是人为的。
我知道打字稿缩小仍然有很多漏洞,并且每个版本都会添加更多缩小逻辑。但是,仍然很难知道什么是用户错误以及 TypeScript 缩小仍然不支持什么。
我在下面有一个示例,我认为应该推断对象上存在属性,但也许我的逻辑不正确。
类型“{}”上不存在属性“a”。
有人可以澄清为什么在评论点没有推断出该属性吗?
type Example = {
a: number
}
const guard = (example: unknown): example is Example => {
if (
example === undefined ||
example === null ||
typeof example === 'string' ||
typeof example === 'number' ||
Array.isArray(example)
) {
return false
}
if ((example as Example).a === undefined) {
return false
}
// I expect narrowing to infer example as {a: unknown}
// due to the if statement above
// TS Error; Property 'a' does not exist on type '{}'.
if (typeof example.a !== 'number') {
return false
}
return true
}
const example: unknown = {
a: 2
}
const result = guard(example)
我也尝试过
if (a.hasOwnProperty('a')) {
return false
}
和
if (Object.hasOwn(example, 'a')) {
return false
}
首先,这是编写此保护函数的一种复杂方法。 我会用这个代替:
type Example = {
a: number
}
const guard = (example: unknown): example is Example => {
if (example === null || typeof example !== 'object') {
return false
}
return ('a' in example && typeof example.a === 'number');
}
const example: unknown = {
a: 2
}
const result = guard(example);
console.log(result);
您使用了类型断言并对强制转换变量进行了未定义检查。这不会缩小原始变量
example
比较:
function chceckX1(x: unknown) {
if (x === '123') {
// x: '123'
}
}
function chceckX1(x: unknown) {
if (x as string === '123') {
// x: unknown, no narrowing on x
}
}
function chceckX2(x: unknown) {
const z = x as string;
if (z === '123') {
// z: '123'
}
}
因此,您可以通过引入变量来修改代码
// Do not use, complex and confusing
const guard = (example: unknown): example is Example => {
if (
example === undefined ||
example === null ||
typeof example === 'string' ||
typeof example === 'number' ||
Array.isArray(example)
) {
return false
}
const exampleCasted = example as Example
if (exampleCasted.a === undefined) {
return false
}
if (typeof exampleCasted.a !== 'number') {
return false
}
return true
}
请注意,虽然这可以正确检查输入对象的形状,但不会发生缩小 -
exampleCasted
是 Example
,这可能是不正确的。
TS 允许将数字与 null 进行比较。请参阅 禁止与 null 和 undefined 进行比较,除非它们在严格 null 模式下是有效的情况 #11920 此检查对
exampleCasted
类型没有影响。