【问题标题】:Auto-skip properties not belonging to the type in TypeScript自动跳过不属于 TypeScript 类型的属性
【发布时间】:2018-10-26 22:30:34
【问题描述】:

假设我有以下类型声明:

declare type Point2D = { x: number, y: number }

我从服务器获取一些数据并得到以下信息:

const response = { x: 1.2, y: 3.4, foreign1: 'value', foreign2: 'value' }

是否可以自动忽略所有不属于我的类型的属性?像这样:

const point: Point2D = response // Should skip all props except for 'x' and 'y'

重要的是响应可以有任意数量的外部属性,所以我不能将对象解构与 rest 运算符一起使用。

【问题讨论】:

  • 如果你已经知道你想要的属性,为什么还要使用rest操作符?
  • 简答,不。您在运行时没有关于类型的信息,因此您无法根据其属性创建新对象。

标签: javascript typescript


【解决方案1】:

类型在运行时不可用。

为了让事情变得干燥,可以使用辅助定义对象:

const Point2DDefinition = { x: 1, y: 1 };
type Point2D = typeof Point2DDefinition;

const point: Point2D = Object.entries(response)
.filter(([k]) => Object.keys(Point2DDefinition).includes(k))
.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {} as Point2D);

由于定义对象依赖于推断类型,它有一定的局限性,例如不能使用交集或联合类型(值不能同时是数字和字符串)。

请注意,此代码不包含检查 point 是否具有来自 Point2D 的所有属性,因此从技术上讲,它更像 point: Partial<Point2D>。它也不检查值是否与定义中的类型相同。

可以额外提供这两种检查以确保运行时的类型安全。

或者,Point2D 可以转换为一个类,该类负责在构造时省略不必要的属性。

应明确列出属性:

class Point2D {
    x: number;
    y: number;

    constructor({ x, y }: Point2D) {
        this.x = x;
        this.y = y;
    }
}

可以选择将验证添加到类构造函数中,以确保运行时的类型安全。

不显式列出属性的解决方法是将类与辅助定义对象结合起来迭代对象属性。 Declaration merging 可用于断言Point2D 类具有Point2DDefinition 中列出的所有属性:

type TPoint2D = typeof Point2DDefinition;

interface Point2D extends TPoint2D {};
class Point2D {
    constructor(point: Point2D) {
        for (const k of Object.keys(Point2DDefinition)) {
            // runtime check for value types can also be added
            if (k in point) {
                this[k] = point[k];
            } else {
                throw new TypeError();
            }
        }
    }
}

重要的是响应可以有任意数量的外来属性,所以我不能将对象解构与 rest 运算符一起使用。

对象解构会产生 WET 但类型安全(在编译时)的代码,当然可以用于此目的,例如:

const point: Point2D = (({ x, y }) => ({ x, y }))(response as Point2D);

它不需要属性的...rest,因为它们应该被丢弃。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2018-08-17
    • 1970-01-01
    相关资源
    最近更新 更多