如何防止我的对象的某些字段被类转换器转换

J4N*_*J4N 4 json firebase typescript class-transformer

我正在尝试使用库class-transformer( https://github.com/typestack/class-transformer ) 将 typescript 类序列化为不接受海关类型的 firebase。

问题是一些数据实际上是与 firebase 兼容的数据,例如“坐标”采用 GeoPoint 格式。

我有这个类被序列化:

export abstract class StopStep extends Step {
  id: string;
  name: string;
  description: string;
  pointOfInterest: PointOfInterest | null;
  address: string;
  coordinates: firebase.firestore.GeoPoint;
}
Run Code Online (Sandbox Code Playgroud)

我想防止转换“坐标”字段。它应该存在,只是不是未转换。

我尝试使用@Transform(({value})=>...),但它似乎只是一个“附加”转换,它不允许我保持相同的格式。

我也尝试过Exclude,但是该字段不再存在。

有没有办法用这个库来完成这个?

Mir*_* S. 5

回答:我已经分析和调试了整个TransformOperationExecutor.ts,简单地说,没有内置的方法来抑制这个执行器尝试进行的无数转换。我想也许@Type一起移除装饰器可以实现目标。但是即使缺少类型信息,该库仍然尽可能地尝试将复杂对象转换为普通对象。@Transform(({value})=>...)不工作的原因是,即使对于返回的值,也有多次检查来确定转换后的值是否需要进一步转换为“普通”。

解决方法: 我看到的唯一解决方案是自己构建该功能。我可以提供以下实现来模拟@Ignore功能:

import { classToPlain, ClassTransformOptions, Transform, TransformFnParams } from 'class-transformer';

// New decorator to be used on members that should not be transformed.
export function Ignore() {
    // reuse transform decorator
    return Transform((params: TransformFnParams) => {
        if (params.type == TransformationType.CLASS_TO_PLAIN) {
            // class-transformer won't touch functions,
            // so we use function-objects as container to skip transformation.
            const container = () => params.value;
            container.type = '__skipTransformContainer__';

            return container;
        }
        // On other transformations just return the value.
        return params.value;
    });
}

// Extended classToPlain to unwrap the container objects
export function customClassToPlain<T>(object: T, options?: ClassTransformOptions) {
    const result = classToPlain(object, options);
    unwrapSkipTransformContainers(result);
    return result;
}

// Recursive function to iterate over all keys of an object and its nested objects.
function unwrapSkipTransformContainers(obj: any) {
    for (const i in obj) {
        if (obj.hasOwnProperty(i)) {
            const currentValue = obj[i];
            if (currentValue?.type === '__skipTransformContainer__') {
                // retrieve the original value and also set it.
                obj[i] = currentValue();
                continue;
            }

            // recursion + recursion anchor
            if (typeof currentValue === 'object') {
                unwrapSkipTransformContainers(currentValue);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该解决方案利用类转换器不会转换函数(get/set 函数除外),因为这些函数不是普通对象的一部分。我们重用Transform装饰器来包装我们不想用函数转换的成员。我们还用字符串标记这些函数,__skipTransformContainer__以便以后轻松找到它们,而不会意外调用错误的函数。然后我们编写一个 new customClassToPlain,它首先调用默认值classToPlain,然后对结果调用递归解包函数。调用 unwrap 函数unwrapSkipTransformContainer并递归搜索所有__skipTransformContainer__容器以检索未转换的值。

用法:

export abstract class StopStep extends Step {
  id: string;
  name: string;
  description: string;
  pointOfInterest: PointOfInterest | null;
  address: string;
  @Ignore()
  coordinates: firebase.firestore.GeoPoint;
}

class ExampleStep extends StopStep {/*logic*/}
    
const step = new ExampleStep();
const plain = customClassToPlain(step);
Run Code Online (Sandbox Code Playgroud)