【问题标题】:How to extend anonymous type in Typescript如何在 Typescript 中扩展匿名类型
【发布时间】:2016-08-02 23:51:18
【问题描述】:

当在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}`));

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

【问题讨论】:

    标签: typescript intellisense strong-typing


    【解决方案1】:

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

    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 及其type definitions 中返回交集类型:

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

    【讨论】:

    • 你能分享一个如何导入和使用core-js实现的例子吗?这将帮助像我这样不想在他们的项目中引入自己的 extend() 函数定义的人。谢谢!
    【解决方案2】:

    怎么样:

    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中使用)

    【讨论】:

    • 您仍然在返回值中再次定义种子。怎么样,如果有 5 个参数,map 将添加 1 个参数。那将是多么混乱。
    • @JukkaVaris 所以使用第一个解决方案和接口。没有办法(我知道)以其他方式扩展它
    • 我害怕那个。我的实际用例是使用 RxJS,并且链可能很长。界面图很容易失控。我使用匿名类型来减少我需要编写的代码量,我希望编译器可以根据使用情况推断类型。
    • @JukkaVaris typescript 的全部意义在于声明类型,如果您不想费力去做,那么只需使用 javascript。是的,使用接口定义所有类型会更加冗长,但您会从中受益。
    • 如果你正在使用最新的打字稿,1.8,你不需要显式声明所有类型。有一个称为上下文类型的概念,它将推断函数参数的类型。因此,与我的原始示例相比,您的第二个示例有很多开销。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 2019-01-06
    • 1970-01-01
    相关资源
    最近更新 更多