代码之家  ›  专栏  ›  技术社区  ›  Rico Kahler

TypeScript类型保护:如何断言泛型T的“转换”版本

  •  0
  • Rico Kahler  · 技术社区  · 5 年前

    user-defined type guard 它测试给定的值是否具有给定数组中的所有属性。

    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
    

    type guard . 到目前为止,我得到的是:

    // 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;
    

    playground link


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

    this answer

    我想明确声明我的类型 T RemoveNullables<NonNullable<T>, K> T 可分配给 可删除可删除<不可为空<T>,K>


    1. 我做错了吗?有没有更好的方法来写这种类型的保护?
    0 回复  |  直到 5 年前
        1
  •  2
  •   kaya3 Amit Bera    5 年前

    这似乎符合您的要求:

    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);
    }
    

    几点注意事项

    • T & ... 交叉口类型保证 ExcludeNullable<T, K> T T 从中丢失的 K
    • Exclude 是一种更简单的方法 null undefined 而不是将条件类型与 infer
    • hasAll 功能实现有点。

    Playground Link

    推荐文章