typescript interface initialization
Asked Answered
L

4

70

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.

Lipo answered 1/5, 2014 at 16:31 Comment(0)
E
73

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).

Exam answered 1/5, 2014 at 17:48 Comment(1)
The only syntax that work in TypeScript 2 is const simpleObject = {} as ISimpleObject; as answered by @Inchoation below.Confuse
I
156

Typescript2:

const simpleObject = {} as ISimpleObject;
Inchoation answered 18/7, 2017 at 18:50 Comment(3)
Is this valid? some ts-linting rules warn against this: 'Type assertion on object literals is forbidden, use a type annotation instead'Cudweed
This worked for me on Angular 5.2.5/TypeScript 2.6.2 Thank youGlare
it works for me by using the code like this restaurant:{ id: 0 }Sat
E
73

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).

Exam answered 1/5, 2014 at 17:48 Comment(1)
The only syntax that work in TypeScript 2 is const simpleObject = {} as ISimpleObject; as answered by @Inchoation below.Confuse
P
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();
    
Paduasoy answered 1/5, 2014 at 16:40 Comment(3)
it depends on what you need to do. Since you cant "new" an interface, you can only cast pocos and let the typescript compiler watch that you are doing stuff right..Paduasoy
The problem with pojos is that the compiler doesn't tell me if the parameters are correct, so if i write fooo instead of foo i don't receive any warning. Am I correct?Lipo
The compiler will tell you the you are not correct if your not using the "type" correctly. My example shows that the compiler will tell you when you are missing mandatory properties in your poco. You can use a nullable type in order to make the property optional(something like prop2? : number will tell the ts compiler that prop2 is a number but isn't mandatory as a property in your object).Paduasoy
D
0

Use generics :

const simpleObject = <ISimpleObject >{};
Dorothi answered 23/11, 2023 at 18:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.