如何将javascript对象减少为仅包含接口的属性

时间:2015-08-05 10:30:59

标签: javascript angularjs typescript

使用typescript时,声明的接口可能如下所示:

interface MyInterface {
  test: string;
}

具有额外属性的实现可能是这样的:

class MyTest implements MyInterface {
  test: string;
  newTest: string;
}

示例(此处变量'reduced'仍然包含属性'newTest'):

var test: MyTest = {test: "hello", newTest: "world"}

var reduced: MyInterface = test; // something clever is needed

问题

一般来说,如何使'reduced'变量只包含'MyInterface'接口中声明的属性。

为什么

尝试在将angular.toJson发送到休息服务之前使用'reduced'变量时会出现问题 - toJson方法会转换newTest变量,即使它在编译期间无法在实例上访问,这也会导致休息服务不接受json,因为它有不应该存在的属性。

8 个答案:

答案 0 :(得分:5)

这是不可能的。原因是interface是Typescript构造,而transpiled JS code为空

//this code transpiles to empty!
interface MyInterface {
  test: string;
}

因此,在运行时没有什么要“使用”的-没有要询问的属性。

@jamesmoey的回答说明了一种实现所需结果的解决方法。 我使用的类似解决方案只是将“接口”定义为类-

class MyInterface {
  test: string = undefined;
}

然后,您可以使用lodash从“接口”中选择属性以注入到您的对象中:

import _ from 'lodash';  //npm i lodash

const before = { test: "hello", newTest: "world"};
let reduced = new MyInterface();
_.assign(reduced , _.pick(before, _.keys(reduced)));
console.log('reduced', reduced)//contains only 'test' property

请参阅JSFiddle

这是一个务实的解决方案,对我很有帮助,而又不会陷入有关它实际上是接口和/或命名约定(例如IMyInterfaceMyInterface)的语义上,并允许您模拟和单元测试

答案 1 :(得分:2)

TS 2.1具有对象传播和休息,因此现在可以:

var my: MyTest = {test: "hello", newTest: "world"}

var { test, ...reduced } = my;

之后,减少将包含除“test”之外的所有属性。

答案 2 :(得分:1)

在您的示例中, newTest 属性无法通过简化变量访问,因此这是使用类型的目标。打字稿带来了类型检查,但它不会操纵对象属性。

答案 3 :(得分:1)

您是否只尝试设置/分配界面上列出的属性?类似的功能在TypeScript中不可用,但编写一个函数来执行您要查找的行为非常简单。



interface IPerson {
    name: string;
}

class Person implements IPerson {
	name: string = '';
}
class Staff implements IPerson {
	name: string = '';
    position: string = '';
}

var jimStaff: Staff = {
    name: 'Jim',
    position: 'Programmer'
};

var jim: Person = new Person();
limitedAssign(jimStaff, jim);
console.log(jim);

function limitedAssign<T,S>(source: T, destination: S): void {
    for (var prop in destination) {
        if (source[prop] && destination.hasOwnProperty(prop)) {
            destination[prop] = source[prop];
        }
    }
}
&#13;
&#13;
&#13;

答案 4 :(得分:0)

  

一般来说,如何才能减少&#39;变量只包含在&#39; MyInterface&#39;中声明的属性。接口

由于TypeScript是结构,这意味着包含相关信息的任何内容都是Type Compatible,因此是可分配的。

也就是说,TypeScript 1.6将获得一个名为freshness的概念。这样可以更容易地捕获清晰的拼写错误(注意新鲜度仅适用于对象文字):

// ERROR : `newText` does not exist on `MyInterface`
var reduced: MyInterface = {test: "hello", newTest: "world"}; 

答案 5 :(得分:0)

简单的例子:

let all_animals = { cat: 'bob', dog: 'puka', fish: 'blup' };
const { cat, ...another_animals } = all_animals;
console.log(cat); // bob

答案 6 :(得分:0)

一种解决方案可能是使用 class 而不是 interface 并使用 factory method(返回其类型的新对象的公共静态成员函数)。模型是您知道允许的属性的唯一地方,也是您不会忘记在模型更改时意外更新它们的地方。

class MyClass {
  test: string;

  public static from(myClass: MyClass): MyClass {
    return {test: myClass.test};
  }
}

示例:

class MyTest extends MyClass {
  test: string;
  newTest: string;
}

const myTest: MyTest = {test: 'foo', newTest: 'bar'};
const myClass: MyClass = MyClass.from(myTest);

答案 7 :(得分:-4)

可能是以下的副本:

TypeScript or JavaScript type casting

您必须将您的值“转换”为其他类型。

一些很好的例子也在这里:http://blogs.microsoft.co.il/gilf/2013/01/18/using-casting-in-typescript/

this.span = <HTMLSpanElement>document.createElement('span');
希望这有帮助吗?