将对象为未定义键 T 的数组过滤到类型为 guard 的 T 的数组 // 可以使用不同子类型的约束进行实例化

Filter array with object of undefined keys T with type guard to T's with defined keys // could be instantiated with a different subtype of constraint

提问人:Patrick 提问时间:11/1/2023 最后编辑:Patrick 更新时间:11/2/2023 访问量:80

问:

目标: 筛选未定义的值类型安全

  // Key b can be missing in this type:
  type AB_ = { a: string; b?: string | undefined, c?: string };
  // Key b can no longer be missing but its value type is unchanged
  type AB = { a: string, b: string | undefined, c?: string };

  const abs: AB_[] = [{ a: '', b: '' }, { a: '', c: '' }];
  const as: AB[] /* Type narrowed! */ = abs.filter(x => filterUndefinedKeys('b', x));
  // as === [{ a: '', b: '' }];

我想过滤密钥不存在的所有情况。请注意,密钥仍然可以选择存在。bc

export function filterUndefinedKeys<
  TValue extends { Key?: any },
  JValue extends { Key: any },
  Key extends string,
>(key: Key, value: TValue): value is JValue {
  return key in value
}

但是,我收到一个错误。

TS2677: A type predicate's type must be assignable to its parameter's type.
Type  JValue  is not assignable to type  TValue 
 JValue  is assignable to the constraint of type  TValue , but  TValue  could be instantiated with a different subtype of constraint  { Key?: any; } 

如何在不使用 的情况下让打字稿识别类型中存在的键?as


示例测试用例

// Tests types: https://www.totaltypescript.com/how-to-test-your-types
type Expect<T extends true> = T;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
  ? 1
  : 2
  ? true
  : false;

describe('filterHasNotUndefinedKeys()', () => {
  it('filters undefined keys', () => {
    // Arrange
    type Input = { a: string; b?: string | undefined; c?: string };
    type Output = { a: string; b: string | undefined; c?: string };
    const input: Input = { a: 'a', b: 'b', c: 'c' };

    // Act
    const output = [input].filter(filterHasNotUndefinedKeys('b'));

    // Assert
    type _ = Expect<Equal<Output, typeof output>>;
  });
});
TypeScript 泛型 undefined

评论

0赞 merryweather 11/1/2023
我认为这里存在一些层面的误解。1) filterUndefinedKeys 应该返回一个函数,如果你想这样使用它。2) 您正在尝试将一个可为 null 的值分配给您的类型谓词中的不可为 null 的值,这是不安全的。3)这有点棘手,因为只是检查键是否存在于对象中。如果没有 ,则您的类型允许键以值 存在。value is JValueinexactOptionalPropertyTypes{ Key?: any }undefined
0赞 merryweather 11/2/2023
一个潜在的解决方案可能如下所示: tsplay.dev/mbyr3N - 请注意,这在结构上等同于 。Required<MaybeB>HasB
0赞 Patrick 11/2/2023
@katniss 谢谢,我只是在检查您的解决方案。1)我知道这一点,但试图降低复杂性。我修复了用例。3) 我知道这些值仍然可以是 ,但是 .null | undefined(a.key === undefined) === (key in a)
0赞 Patrick 11/2/2023
@katniss我不确定 2) 有什么问题?在这种情况下,您的解决方案是正确的,但我希望能够使一个额外的属性成为必需的。type-fest 中的 SetRequired 将创建这样的类型。我将调整我的示例以反映此用例。
0赞 ekim boran 11/2/2023
@Patrick这是你想要的吗?tsplay.dev/m3oqqm

答: 暂无答案