typescript - RxJS:确保定义了可选对象属性

标签 typescript rxjs undefined rxjs-observables

我需要一个 RxJS 运算符来检查对象上的属性是否存在,然后更改类型以正确反射(reflect)这一点。

我已经有一个运算符可以对发出的值执行此操作:

const notUndefined = <T>() =>
  filter<T | undefined, T>(
    (x): x is T extends undefined ? never : T => x !== undefined
  );

但我还需要能够对其属性之一执行此操作,可以使用如下所示的属性:

interface MyInterface {
  myKey?: string;
}

of<MyInterface>({ myKey: "Some value" }).pipe(
  notUndefinedKey("myKey"),
  map((x) => x.myKey)
  //           ^? (property) myKey: string
)

of<MyInterface>({ myKey: "Some value" }).pipe(
  map((x) => x.myKey)
  //           ^? (property) MyInterface.myKey?: string | undefined
)

我已经有了第一个工作版本,但它似乎有点过分,而且似乎还从对象中删除了方法:

import { OperatorFunction, filter, of, map } from "rxjs";

// Typescript types helper
type DefinedFields<TType> = {
  [TKey in keyof TType]-?: DefinedFields<NonNullable<TType[TKey]>>;
};

type WithDefinedKey<TType, TKey extends keyof TType> = Omit<TType, TKey> & DefinedFields<Pick<TType, TKey>>;

type OperatorToDefinedKey<TType, TKey extends keyof TType> = OperatorFunction<
  TType | undefined,
  WithDefinedKey<TType, TKey>
>;

// Operator
export const notUndefinedKey = <TType, TKey extends keyof TType>(
  key: TKey
): OperatorToDefinedKey<TType, TKey> =>
  filter<TType>((x) => x?.[key] !== undefined) as OperatorToDefinedKey<
    TType,
    TKey
  >;

有什么好的方法可以做到这一点吗?一个可能还保留更多原始接口(interface)(例如对象上的方法)的对象?

Playground Link

最佳答案

您可以大大简化这个函数,因为我认为声明所有这些类型对您来说没有多大作用。下面的函数返回一个与传递的值类型相同的值,并且属性 key 的值已明确定义。

function notUndefinedKey<T, U extends keyof T>(key: U): OperatorFunction<T, T & { [K in U]-?: T[U] }> {
  return filter((x): x is T & { [K in U]-?: T[U] } => x[key] != null);
}

用法示例

from([{}, { ignoreMe: 'Nope'}, {myKey: 'I am defined'}] as MyInterface[]).pipe(
  notUndefinedKey ('myKey'),
).subscribe(x => console.log(x.myKey));
// output: I am defined

替代方案

如果您确实想要定义的类型(可能是因为语法看起来有点困惑),您可以执行以下操作:

type NotUndefinedKeys<T, U extends keyof T> = T & { [K in U]-?: T[U] }

function notUndefinedKey<T, U extends keyof T>(key: U): OperatorFunction<T, NotUndefinedKeys<T, U>> {
  return filter((x): x is NotUndefinedKeys<T, U> => x[key] != null);
}

您还可以使用多个键来完成此操作,这可能是最灵活的用法,并且不需要太多更改。使用运算符根本不会改变 - 您可以传递单个 key 或多个 key 。运算符更改非常简单:接受类型的扩展运算符,更改过滤器函数的工作方式,然后 TypeScript 发挥其魔力。

function notUndefinedKeys<T, U extends keyof T>(...keys: U[]): OperatorFunction<T, T & { [K in U]-?: T[U] }> {
  return filter((x): x is T & { [K in U]-?: T[U] } => keys.every(k => x[k] != null));
}

StackBlitz

关于typescript - RxJS:确保定义了可选对象属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76565212/

相关文章:

javascript - 我如何解析另一个 Observable 中的一个 Observable? - RXJS

node.js - 为什么 async/await 在我的代码中不起作用?

java - 检查 javascript 函数是从 java applet 定义的

javascript - 带有 RequireJs 和 TypeScript 的 KnockoutJs 组件

Angular loadChildren 属性模块的绝对路径不起作用

rxjs - 检索 Observable 订阅者并让他们订阅另一个 Observable

redux - 返回 EMPTY 崩溃我的 redux 可观察链

typescript - 如何将对象属性名称数组映射到给定对象中名称所指向的值数组

javascript - TypeScript 100.0% 是如何用 TypeScript 编写的?

php - 引用 MySQL 元素时 PHP 中 undefined variable