如何在 Typescript 中扩展匿名类型

How to extend anonymous type in Typescript

typescript 中使用匿名类型链接功能时,例如:

  let array = [{ seed: 2 }, { seed: 3 }];
  array
    .map(i => ({ seed: i.seed, square: i.seed * i.seed }))
    .forEach(i => console.log(`square for ${i.seed} is ${i.square}`));

我需要为地图函数定义新的匿名类型。如果我有多个步骤来生成新属性,我最终会编写大量定义代码来获取所有属性。 我可以使用 $.extend(或 Object.assign),但那样我将失去智能感知和强类型。

  array
    .map(i => $.extend(i, { square: i.seed * i.seed }))
    .forEach(i => console.log(`square for ${i.seed} is ${i.square}`));

如何在不重新定义所有属性的情况下扩展匿名对象,同时保持强类型?

怎么样:

interface A {
    seed: number;
}

interface B extends A {
    square: number;
}

let array: A[] = [{ seed: 2 }, { seed: 3 }];
array
    .map<B>(a => { 
        return { seed: a.seed, square: a.seed * a.seed } 
    })
    .forEach(b => console.log("square for ${b.seed} is ${b.square}"));

或(如果您想匿名):

let array = [{ seed: 2 }, { seed: 3 }];
array
    .map<{seed: number, square: number}>(a => {
        return { seed: a.seed, square: a.seed * a.seed }
    })
    .forEach(b => console.log("square for ${b.seed} is ${b.square}"));

(在playground中使用)

我终于找到了解决办法。这可以通过 Intersection Types 来实现。这些可以与匿名类型和 类 一起使用。在下面的示例中,扩展函数将从每个对象和 return 交叉类型的对象复制属性。这将在不丢失智能感知和强类型的情况下减少大量类型定义代码。

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

let array = [{ seed: 2 }, { seed: 3 }];

array
    .map(i => extend(i, { square: i.seed * i.seed }))
    .map(i => extend(i, { cube: i.square * i.seed }))
    .forEach(i => console.log(`square for ${i.seed} is ${i.square} and cube is ${i.cube}`));

Playground

中相同

已实施 f.e。在 core-js and its type definitions return 交叉点类型:

assign<T, U>(target: T, source: U): T & U;

为了添加和更容易理解关于如何使用 intersection types 扩展匿名类型的答案,我做了这个例子来说明它:

interface Animal {
  name: string
}

// With named types:

interface Bear extends Animal {
  honey: boolean
}

function giveHoney(bear: Bear) {
  bear.honey = true;
}

const myBear: Bear = { name: 'Bob', honey: false };
giveHoney(myBear);

// With anonymous types (no need to explicitly define the Bear type):

function giveHoney(bear: Animal & { honey: boolean }) {
  bear.honey = true;
}

const myBear = { name: 'Bob', honey: false };
giveHoney(myBear);