TypeScript接口初始化

67

我的 TypeScript 水平是“绝对初学者”,但我有很好的面向对象编程背景。我正在使用 TypeScript 构建一个引用外部 t.ds 库的应用程序,该库包含以下接口:

interface ISimpleObject {
    foo: string;
    bar?: any;
}

现在,如果我想调用一个具有IRequestConfig参数的方法,我该如何创建一个?我可以看到不同的选项:

  1. 创建ISimpleObject的简单实现。我不喜欢这种方法,因为它看起来像样板代码。
  2. 不初始化对象(我担心这可能会破坏某些东西...):

    var x: IsimpleObject; x.bar = 'xxx'; callMethod(x);

  3. 将普通对象转换为指定类型:

    var x: IsimpleObject = <IsimpleObject>{foo: 'yyy', bar: 'xxx'};

    我也不喜欢这种方法,因为它不能强制执行类型安全性......

我想这是一个相当琐碎的问题,我可能错过了一些关于TypeScript的琐碎细节。

4个回答

152

Typescript2:

const simpleObject = {} as ISimpleObject;

4
这个是否有效?一些 ts-lint 规则警告说:“禁止在对象字面量上使用类型断言,应该使用类型注释代替。” - J_Ocampo
这对我在Angular 5.2.5 / TypeScript 2.6.2上有效。谢谢。 - Let A Pro Do IT

72
如果您有这样一个接口:

如果您有这样一个接口:

interface ISimpleObject {
    foo: string;
    bar?: any;
}

此接口仅在编译时和代码提示/智能感知中使用。接口用于以一致的方式提供具有定义签名的对象的严格和类型安全的使用方法。

如果您有一个使用上述interface的函数:

function start(config: ISimpleObject):void {

}

TypeScript编译将会失败,如果一个对象没有ISimpleObject接口的完全签名。

调用函数start有多种有效方法:

// matches the interface as there is a foo property
start({foo: 'hello'});

// Type assertion -- intellisense will "know" that this is an ISimpleObject
// but it's not necessary as shown above to assert the type
var x = <ISimpleObject> { foo: 'hello' }; 
start(x);

// the type was inferred by declaration of variable type
var x : ISimpleObject = { foo: 'hello' };  
start(x);

// the signature matches ... intellisense won't treat the variable x
// as anything but an object with a property of foo. 
var x = { foo: 'hello' };
start(x);    

// and a class option:
class Simple implements ISimpleObject {
    constructor (public foo: string, public bar?: any) {
       // automatically creates properties for foo and bar
    }
}
start(new Simple("hello"));

无论何时签名不匹配,编译都会失败:
// compile fail
var bad = { foobar: 'bad' };
start( bad );

// compile fail
var bad: ISimpleObject = { foobar: 'bad' };

// and so on.

没有"正确"的方法去完成它,这是一种风格选择。如果它是一个被构造的对象(而不仅仅是直接作为参数传递),我通常会声明类型:

var config: ISimpleObject = { foo: 'hello' };

那么代码补全/智能感知功能将会在我使用config变量的任何地方生效:
config.bar = { extra: '2014' };

在TypeScript中没有"casting"的概念。它被称为类型断言,并且在这里描述的情况下不应该需要使用(我在上面提供了一个可以使用它的例子)。在这种情况下,不需要声明变量类型,然后再使用断言(因为类型已经是已知的)。

1
在TypeScript 2中唯一有效的语法是const simpleObject = {} as ISimpleObject;,正如@sdrevk所回答的那样。 - Rosdi Kasim

3
  • You can't create an instance of an interface since Typescript doesn't "translate" it into js. You can check the js that is created and you will see nothing in it. It's simple for compile errors, type safety and intelisense.

    interface IStackOverFlow
    {
       prop1 : string;
       prop2 : number;
    }
    
    public MyFunc(obj : IStackOverFlow)
    {
        // do stuff
    }
    
    var obj = {prop1: 'str', prop2: 3};
    MyFunc(obj); // ok
    
    var obj2 = {prop1: 'str'};
    MyFunc(obj); // error, you are missing prop2
    
    // getObj returns a "any" type but you can cast it to IStackOverFlow. 
    // This is just an example.
    var obj = <IStackOverFlow> getObj();
    

1
这取决于你需要做什么。由于你不能“new”一个接口,你只能转换pocos并让TypeScript编译器监视你是否正确地执行操作。 - Amir Popovich
POJO的问题在于编译器无法告诉我参数是否正确,因此如果我写成fooo而不是foo,就不会收到任何警告。我的理解正确吗? - Giacomo Tagliabue
如果你没有正确使用“类型”,编译器会告诉你不正确。我的示例表明,如果在poco中缺少强制属性,编译器会告诉你。您可以使用可空类型来使属性成为可选项(例如,prop2?:number会告诉ts编译器prop2是一个数字,但不是对象中必需的属性)。 - Amir Popovich

0
使用泛型:
const simpleObject = <ISimpleObject >{};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接