¿Cómo combinar propiedades de objetos en mecanografiado?

82

Me gustaría saber la mejor manera de hacer esto, digamos que tengo dos objetos

var objectA = {
    propertyA: 1,
    propertyB: 2
    ...
    propertyM: 13
}

var objectB = {
    propertyN: 14,
    propertyO: 15
    ...
    propertyZ: 26
}

Si objectC es creado por

var objectC = Object.assign(objectA, objectB);

¿Cómo puedo declarar / describir objectC, para que el compilador / IDE sepa que tiene las propiedades de objectA y objectB?

Me gustaría encontrar una manera sin la necesidad de definir interfaces para objectA y objectB. No quiero escribir una declaración y una definición / evaluación para la misma propiedad dos veces. Esta redundancia es significativa si tengo demasiadas propiedades en un objeto.

(¿Existe un operador que pueda extraer la interfaz / tipo de un objeto existente?)

¿Es posible?

WawaHermano
fuente

Respuestas:

155

Parece que esto debería hacer el truco:

var objectA = {
    propertyA: 1,
    propertyB: 2,
    .
    . // more properties here
    .
    propertyM: 13
};

var objectB = {
    propertyN: 14,
    propertyO: 15,
    .
    . // more properties here
    .
    propertyZ: 26
};

var objectC = {...objectA, ...objectB}; // this is the answer

var a = objectC.propertyA;

var n = objectC.propertyN;

Basado en este artículo: https://blog.mariusschulz.com/2016/12/23/typescript-2-1-object-rest-and-spread


Además, el orden de las variables en la descomposición es importante. Considera lo siguiente:

var objectA = {
    propertyA: 1,
    propertyB: 2, // same property exists in objectB
    propertyC: 3
};

var objectB = {
    propertyX: 'a',
    propertyB: 'b', // same property exists in objectA
    propertyZ: 'c'
};

// objectB will override existing properties, with the same name,
// from the decomposition of objectA
var objectC = {...objectA, ...objectB}; 

// result: 'b'
console.log(objectC.propertyB); 

// objectA will override existing properties, with the same name,
// from the decomposition of objectB
var objectD = {...objectB, ...objectA}; 

// result: '2'
console.log(objectD.propertyB); 
Alkasai
fuente
4
solo para mejorar la respuesta: esta línea hace el truco: var objectC = {... objectA, ... objectB};
Amirreza
Quiero actualizar la propiedad de objectA si existe la misma clave en ambos objetos. Significa que si la clave es la misma, entonces debería tomar la propiedad de objectB. ¿Como es posible?
Ankur Akvaliya
Lea los comentarios en mi respuesta. Básicamente se construye propiedades de izquierda a derecha, donde cada nueva información reemplaza la existente: var objectC = {...objectA, ...objectB};. El formulario de objectBpropiedades anulará las propiedades que ya fueron asignadas objectA, si las propiedades tienen el mismo nombre.
Alkasai
Esto funciona, por lo tanto, responde OP, sin embargo, mi preocupación es que no hay ningún tipo asociado ahora a objectD u objectC, cuando intenta escribirlo explícitamente en algo (suponga que hay tal tipo), no funcionará. ¿Existe una forma segura de hacer esto?
Srivathsa Harish Venkataramana
@SrivathsaHarishVenkataramana los tipos se infieren de la asignación. Entonces objectC tendrá propertyB: string, mientras que objectD lo inferirá como propertyB: number. Puede escribir manualmente ambos C y D: type ABC = { propertyA: number; propertyB: string | number; propertyC: number; propertyX: string; propertyZ: string; }o solo uno de ellos estableciendo propertyB en cadena o en número.
Alkasai
10

¿Entonces el compilador / IDE sabe que tiene las propiedades de objectA y objectB?

Utilice un tipo de intersección + genéricos. Ej. De aquí

/**
 * Quick and dirty shallow extend
 */
export function extend<A>(a: A): A;
export function extend<A, B>(a: A, b: B): A & B;
export function extend<A, B, C>(a: A, b: B, c: C): A & B & C;
export function extend<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;
export function extend(...args: any[]): any {
    const newObj = {};
    for (const obj of args) {
        for (const key in obj) {
            //copy all the fields
            newObj[key] = obj[key];
        }
    }
    return newObj;
};

Más

Ambos se mencionan aquí: https://basarat.gitbooks.io/typescript/content/docs/types/type-system.html

basarat
fuente
Gracias. Esto parece funcionar. Sin embargo, la función extend () está definida en una biblioteca de terceros, ¿hay alguna forma de sobrescribir esta definición específica para extender () en su archivo d.ts? (Estoy usando subrayado _.extend ()).
WawaBrother
Sip. Solo modificarunderscore.d.ts
basarat
4

(¿Existe un operador que pueda extraer la interfaz / tipo de un objeto existente? ¿Es posible?)

Deberías optar por typeof .

type typeA = typeof objectA;
type typeB = typeof objectB;

Para fusionarlos, puede usar la operación de intersección como ya se señaló basarat.

type typeC = typeA & typeB
Hav
fuente
3

prueba esto..

const person = { name: 'TRilok', gender: 'Male' };
const tools = { computer: 'Mac', editor: 'Atom' };
const attributes = { handsomeness: 'Extreme', hair: 'Brown', eyes: 'Blue' };

const summary = {...person, ...tools, ...attributes};
Trilok Singh
fuente