TypeScript定义用于合并对象,但阻止对象属性中不同类型的合并

伦纳德·菲

我想编写一个函数,用另一个对象扩展一个对象。例如:我们将调用一个对象src再调用另一个对象ext该函数必须返回(复制)src对象,但是对象对象深度(递归)扩展ext如果的一个(子)属性的数据类型与(子)属性ext的类型不匹配,则src该函数必须忽略该ext值。中的新属性ext(不存在src)将添加到结果对象中。

为了更好地理解这里的完整示例:

/** A helper definition to build indexable objects */
interface indexObject<T> {
    [key: string]: T
}

type SafelyMergedObject<Src extends indexObject<any>, Ext extends indexObject<any>> = {
    // The searched type definition
}

const src= {
    a: "a",
    b: "b",
    c: false,
    d: {
        a: "Alice",
        b: "Bob",
    }
}
const ext = {
    a: ["a"],
    b: 1,
    c: true,
    d: {
        a: "Ann",
        c: "Clair",
    },
    e: "New value",
}
const result: SafelyMergedObject<typeof src, typeof ext> = {
    a: "a", /** Only string should be allowed here because
                it's the property type of the source (Src) type */
    b: "b", /** Same as above (`a` property) */
    c: true,/** Since `c` has the same data type the function
                should return the property value of the `ext`
                object */
    d: {    /** Same data type in both objects */
        a: "Ann",   /** new value from `ext` */
        b: "Bob",   /** copied value from `src` */
        c: "Clair", /** new property from `ext` */
    },
    e: "New Value", /** new property from `ext` */
}

TypeScript游乐场链接

我知道如何编写函数。这很容易,但是我不知道如何编写此类型定义。那有可能吗?

默认的TypeScript类型推断行为不适合我的问题,因为类型是递归的,并且比简单object类型更复杂例如,我将使用该功能将用户特定的配置加载到我的应用中。用户配置可能已损坏。因此,我必须将默认配置与用户特定的配置合并。

贾卡尔兹

我将按以下方式解释您的要求:对于对象类型TU,对象类型SafelyMergedObject<T, U>应具有与相同的键T & U,但属性类型有所不同。如果某个键同时K存在TU存在,则按原样使用属性(因此与相同T & U)。如果键K既存在又存在,T并且U两个属性类型中的至少一个不是对象,则使用from中的属性类型,T而忽略from中的属性U如果密钥K中既存在TU一个对象类型在两个TU,然后递归分解成经由该属性SafelyMergedObject<T[K], U[K]>

这被翻译成类似:

type SafelyMergedObject<T, U> = (
    Omit<U, keyof T> & { [K in keyof T]:
        K extends keyof U ? (
            [U[K], T[K]] extends [object, object] ?
            SafelyMergedObject<T[K], U[K]>
            : T[K]
        ) : T[K] }
) extends infer O ? { [K in keyof O]: O[K] } : never;

在这里我们首先输出Omit<U, keyof T>,这是U中不存在的属性T然后,我们将遍历的键T,并输出T[K]该属性是否不在中U,或者如果该属性在其中U但至少是一个T[K]U[K]不是一个对象,则输出。

这里唯一的“把戏”是extends infer O ? {[K in keyof O]: O[K]} : never所有这些都是通过迭代所有键并将结果合并为单个对象类型来“修饰”或“扩展”对象类型。

让我们看看您的srcext值的作用:

type Result = SafelyMergedObject<typeof src, typeof ext>;

如果您将鼠标悬停在IntelliSense上,则会看到:

type Result = {
    e: string;
    a: string;
    b: string;
    c: boolean;
    d: {
        c: string;
        a: string;
        b: string;
    };
}

我想这就是您想要的。请注意,如果我不包括该extends infer O...行,则该Result类型将被评估为:

type Result = Pick<{
    a: string[];
    b: number;
    c: boolean;
    d: {
        a: string;
        c: string;
    };
    e: string;
}, "e"> & {
    a: string;
    b: string;
    c: boolean;
    d: SafelyMergedObject<{
        a: string;
        b: string;
    }, {
        a: string;
        c: string;
    }>;
}

尽管它属于同一类型,但很难理解。


请注意,如果您SafelyMergedObject<T, U>在不同情况下使用上述方法可能会出现各种边缘情况。您需要确定在这些情况下输出的外观,并可能需要调整定义才能使输出变为现实。所以要小心

好的,希望能有所帮助;祝好运!

操场上的代码链接

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

合并相同类型的对象

如何使用 Java 8 合并两个不同类型的自定义对象列表

rxjava合并不同类型的可观察对象

数据框中的不同类型的合并

Typescript 合并了数组中具有不同负载的两个对象的类型

当属性是不同的对象类型时,将代码合并到基类中

合并数组中的对象属性

在 Typescript 中合并可区分的对象类型联合

从对象数组中的对象属性合并数组

未知对象合并的Typescript返回类型

Typescript,合并元组元素的对象类型

在Typescript中,如何将通用容器类型的对象合并到对象类型的通用容器中?

在相同类型的java中合并两个对象列表

数组中不同类型的对象并获取每个对象的类型

访问属性,存储在对象类型Arraylist中的不同类对象的方法

通过相等属性合并对象,并在同一数组中通过不同属性合并对象

在条件查询规范中合并不同类型的规范

如何在Haskell中合并不同类型的地图?

合并Pandas Dataframe中不同类型的列

如何在Typescript中正确定义具有不同类型的值的对象

分配具有不同类型属性的对象的属性

在 Angular 中合并来自不同服务的对象

合并 Typescript 中对象内的数组

根据属性合并数组中的对象

电源外壳。合并数组中对象的属性

如何基于属性合并数组中的对象

合并对象数组的相同属性,并在该对象数组中为不同属性创建对象数组

排序不同类型的对象

R中的“ identical()”函数有问题吗?“ identical()”如何用于不同类型的对象?