typescript interface initialization

2020-02-17 05:36发布

问题:

My level of typescript is 'ABSOLUTE BEGINNER' but I have a good OOP background. I am building an with typescript that reference an external t.ds library that contains the following interface:

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

Now, if I want to call a method that has an IRequestConfig parameter, how do I create one? I can see different options:

  1. Create a simple implementation of ISimpleObject. I don't like this approach because it looks like boilerplate code to me
  2. don't initialize the object (I fear this could break something...):

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

  3. Cast a pojo:

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

    I don't like this approach either because it doesn't enforce type safety...

I guess this is a fairly trivial question and I am missing something trivial about typescript.

回答1:

If you have an interface like:

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

This interface is only used at compile time and for code-hinting/intellisense. Interfaces are used to provide a rigorous and type-safe way of using an object with a defined signature in a consistent manner.

If you have a function using the interface defined above:

function start(config: ISimpleObject):void {

}

The TypeScript compile will fail if an object does not have the exact signature of the ISimpleObject interface.

There are multiple valid techniques for calling the function 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"));

Any time the signature doesn't match, the compile will fail:

// compile fail
var bad = { foobar: 'bad' };
start( bad );

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

// and so on.

There is no "right" way to do it. It's a matter of style choice. If it were an object that was constructed (rather than just directly passed as a parameter), I'd normally declare the type:

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

That way code-completion/IntelliSense will work anywhere I used the config variable:

config.bar = { extra: '2014' };

There is no "casting" in TypeScript. It is called a type assertion and shouldn't be needed in the cases described here (I included an example above where it could be used). There's no need to declare the variable Type and then use an assertion in this case (as the type was already known).



回答2:

Typescript2:

const simpleObject = {} as ISimpleObject;


回答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();