Typescript用户定义的类型保护检查对象具有数组中的所有属性

2024-02-20

我正在尝试写一个用户定义的类型保护 https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards测试给定的值是否具有给定数组中的所有属性。

我正在调用这个函数hasAll它在 Javascript 中的实现和使用如下所示:

function hasAll(obj, keysToCheck) {
  if (!obj) return false;

  for (const key of keysToCheck) {
    const value = obj[key];
    if (value === null) return false;
    if (value === undefined) return false;
  }

  return true;
}

hasAll({ foo: 'test', bar: 5 }, ['foo', 'bar']); // true

hasAll({ foo: 'test', bar: 5 }, ['foo', 'bar', 'baz']); // false

我现在想做的是将上面的函数变成类型保护 https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards。这是我到目前为止所拥有的:

// this _almost_ works ????
type Nullable<T> = T | null | undefined;

type RemoveNullables<T, K extends keyof T> = {
  [P in K]-?: T[P] extends Nullable<infer U> ? U : T[P];
};

function hasAll<T, K extends keyof NonNullable<T>>(
  obj: T,
  keysToCheck: K[],
): obj is RemoveNullables<NonNullable<T>, K> {
  // but i'm getting an error here ????????????
  if (!obj) return false;

  const nonNullableObj = obj as NonNullable<T>;

  for (const key of keysToCheck) {
    const value = nonNullableObj[key];
    if (value === null) return false;
    if (value === undefined) return false;
  }

  return true;
}

export default hasAll;

游乐场链接 https://www.typescriptlang.org/play/index.html#code/C4TwDgpgBAcgrgGwQQwEYIgHgCoD4oC8U2UAPlAHaIJlRwUAmEAZgJYUQMDcAsAFD9QkKACUIAWwD2ANwjwkaDAGccAGigBpKBAAewCIyVQA1hBCTmxfEQDe-KFADaABSjtNAXQC0AfgBcxC4e2noGDEbyKOhY7MwQAE5QAKr4PslQAdhBvHwAvjn8zPQAxsCskhRQABbISgCCSGqaIfqGJmYWsBWRilh4uAAU9lCSqABWmarDpiBK2JIAwlUQxcYBGo4eU3wAlAGjY25GYlKyPdEqMN3UvTi46hr4dnwOrJYDAIQHO1DxEMBweKVZjIBBKCA5BzFCpKYCUa4KaIAeXGhBGqNqXQo5wwdwKLygzEkiQG0IosPaIBGlhmc0Wy1WP2eDihMLh0lBcGgRAoCKiGBRY0cMw8kJZbygAw5CC5hAIPOoPz+AKBhNB4LFr3e0tl8qI9CYbA4DCV-0BwPVEOGuX4w2V5qgwHiXJyNoEfCE0AAYpJJGjmYTff4oLD4uwAOZi1DIeIBKjiVAJWhUJCu23ujBwomSAI+v22XJQTHICggfHZgB00fiFeAkgAyk6IwMdlwoAB6duByRVmNHCgAcjhyA5rH50GWf3TEs+NXqSAG2fUjgH1YHHh2TOGwCq8UkAHdKBBDwBReJ7+IttPuyvV2sNpsUcNXjtd2991hGXmHw3sThQaRWGQR1lkdcAIHDOAYwYIA


错误信息是:

A type predicate's type must be assignable to its parameter's type.
  Type 'RemoveNullables<NonNullable<T>, K>' is not assignable to type 'T'.

我读了这个答案 https://stackoverflow.com/a/50423805/5776910有一个很好的解释,但它并没有真正帮助我的情况。

我想明确断言我的类型T将符合RemoveNullables<NonNullable<T>, K>当它运行完这个函数之后。我真的不在乎是否T可分配给RemoveNullables<NonNullable<T>, K>(如果这是有道理的话)。


  1. 我在这件事上做错了吗?有没有更好的方法来编写这种类型保护?
  2. 如果这种方法没问题,我如何告诉打字稿我不关心类型保护本身是否“不安全”?

这似乎满足您的要求:

type ExcludeNullable<T, K extends keyof NonNullable<T>> = NonNullable<T> & {
    [k in K]-?: Exclude<NonNullable<T>[k], null | undefined>
}

function hasAll<T, K extends keyof NonNullable<T>>(
    obj: T,
    keysToCheck: K[]
): obj is ExcludeNullable<T, K> {
    return obj !== null && obj !== undefined
        && keysToCheck.every(k => obj![k] !== null && obj![k] !== undefined);
}

一些注意事项:

  • The T & ...交集类型保证ExcludeNullable<T, K>可分配给T。如果没有这个,映射类型就不具有以下属性T缺少的K.
  • Exclude是一种更简单的摆脱方法null and undefined比使用条件类型infer.
  • 我冒昧地简化了hasAll函数实现了一下。

游乐场链接 http://www.typescriptlang.org/play/#code/C4TwDgpgBAogHgYwDYFcAmEByKlIIYBGSEAPACoA0UA0lBHMBAHZoDOUA1hCAPYBmUTDybZchYuQB8kqAF5Bw0fiKkyMgGRQA3gCgo+qAG0OUAJZMaAXQC0AfgBcsRKgwkhInMolrjlqk08oAB8oFBYIPnMINEkdAF8dHT4whGBTYSgACzxWAEFccipaekYWdi5eATUACj0DHgIAK0dKOv0K1jIeAGFMiAQOR2pDSx0ASkcGxrN2eGR0LE9xVSKZXQMoACcIYBRNiymoAEJZeQDcNo2odU1Dk-kwjEimaMuNm85uTp6+gYA6CAANwgmxA1RMshkU18x1OUHOSGutyaMPuoXCz2iYwA3PFEqBIFAAGI8HhybSXPikhxQVjATbmADmuI2BDwm0cAQAtgQQcF4Z5cQliMAoFSeI4SWT5Fo4lAcvKmCBcUlSX82Zs-sAeABlelM6o4qAAemNYrVGpmTAA5KK8IC8KYvNA+ttEqYBNUjtk8rhquKqIZrRrrZYxmMKRtgJlNjwAO6wTaxzaGoWJcV-cXYk1mukMpiM-mPCJRNCqnjq9nZ00Cnkg92e705fJIf2kwPW8Wh8ORgzR2MJmBJngpnF48uZ0nV3P6gs6IA

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Typescript用户定义的类型保护检查对象具有数组中的所有属性 的相关文章

随机推荐