动态检查 TypeScript 对象是否有没有自定义类型保护的键

问题描述 投票:0回答:1

如果将键写为字符串文字,我可以使用 TypeScript 的

in
关键字以类型安全的方式检查对象是否具有键:

function guardHasTest <Data extends object> (
  value: Data
): Data & Record<'test', unknown> {
  if (!('test' in value)) {
    throw new Error('Missing key')
  },
  return value
}

但是,如果我将键设为动态字符串,相同的语法不会缩小类型:

function guardHasKey <Data extends object, Key extends string> (
  value: Data,
  key: Key
): Data & Record<Key, unknown> {
  if (!(key in value)) {
    throw new Error('Missing key')
  }
  return value
  // Type 'Data' is not assignable to type 'Data & Record<Key, unknown>'.
  Type 'object' is not assignable to type 'Data & Record<Key, unknown>'.
    Type 'object' is not assignable to type 'Data'.
      'object' is assignable to the constraint of type 'Data', but 'Data' could be instantiated with a different subtype of constraint 'object'.
        Type 'Data' is not assignable to type 'Record<Key, unknown>'.
          Type 'object' is not assignable to type 'Record<Key, unknown>'.ts(2322)
}

我不想使用自定义类型保护,因为它们的逻辑不是类型安全的:

export function isKeyOf<T, const Key extends string>(
  obj: T,
  key: Key
): obj is T & Record<Key, unknown> {
  return true // No error, even though the logic is not correct
}

如何让函数以完全类型安全的方式动态检查对象是否具有键?

typescript types typescript-generics type-safety typeguards
1个回答
0
投票

为了解决在以类型安全的方式检查对象中是否存在动态键时使用 TypeScript 类型系统所面临的问题,您可以改进您的方法。 TypeScript 的类型系统在动态推断类型时有其局限性,特别是当您需要根据运行时条件缩小类型时。

这是使用类型谓词的改进方法。

您希望您的函数验证对象中是否存在键,并且让 TypeScript 了解此检查会影响对象的类型。我们可以通过类型谓词来实现这一点,它允许您通知 TypeScript 如果函数返回 true,则对象值确实将具有 Key 类型的键。

以下是编写此类函数的方法:


function hasKey<Data extends object, Key extends PropertyKey>(
  value: Data,
  key: Key
): value is Data & Record<Key, unknown> {
  return key in value;
}

function ensureHasKey<Data extends object, Key extends PropertyKey>(
  value: Data,
  key: Key
): Data & Record<Key, unknown> {
  if (!hasKey(value, key)) {
    throw new Error(`Missing key: ${key}`);
  }
  return value;
}

类型保护(hasKey):此函数检查对象中是否存在键。它使用类型谓词 value 是 Data & Record,它告诉 TypeScript 如果 hasKey 返回 true,则保证 value 的类型为 Data & Record

确保函数(ensureHasKey):该函数使用hasKey来确保key存在于对象中。如果该键不存在,则会抛出错误。如果该键存在,它将返回该对象作为 Data & Record。由于 hasKey 中的类型谓词,TypeScript 知道如果 EnsureHasKey 完成且没有抛出错误,则返回的对象类型将正确缩小。

使用方法如下

const obj = { name: "Alice", age: 25 };

// This will throw an error if 'age' key is missing
const validatedObj = ensureHasKey(obj, 'age');

// Now TypeScript knows 'validatedObj' has a property 'age'
console.log(validatedObj.age); // 25

// This will throw an error because 'salary' does not exist in 'obj'
const anotherObj = ensureHasKey(obj, 'salary');

这种方法确保了编译时和运行时的类型安全。类型谓词允许 TypeScript 的类型系统理解并相信运行时检查(in 运算符)对于根据键的存在缩小对象类型的范围是有效的。

© www.soinside.com 2019 - 2024. All rights reserved.