26

I have a Interface IBase and a variable that contains a few other objects (in the sample i just added base for a better demonstration)

interface IBase {
    height?:number;
    width?:number;
}

var element = {
    base: {

    }
}

How can I say that the object that the varable element.base has is from the type IBase? I know that I could create a type for the element variable that contains the types of base etc, but is that also a possibility to type that scenario without doing so.

4 Answers 4

32

Van den Brink's answer is good. Just as a demo another option :

var element = {
    base: <IBase> {

    }
}

This will give the desired intellisense as well :

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Using a type assertion here only gets you partial benefits because it will allow you to coerce to a type that your object literal doesn't actually meet the spec for. That is, it gets you intellisense but doesn't get you a good static type check. AFAICT the only way to get a static type check is to assign the literal to a variable of the correct type without a type assertion. Dick van den Brink has the better answer IMO.
12

If you change the declaration of var element to the following it knows what base is:

var element: { base: IBase; } = {
    base: {
    }
}

Note: you can also create a new interface for it like this which makes it a bit more reusable: interface IElement { base: IBase; } and then use it like here: var element: IElement = { base: {} }

Comments

9

The excellent answer from @basarat now needs a little updating; using the angle brackets now produces a tslint error:

[tslint] Type assertion using the '<>' syntax is forbidden. Use the 'as' syntax instead. (no-angle-bracket-type-assertion)

The solution is a simple one:

const element = {
    base: {} as IBase
}

This also provides the intellisense (auto-complete) that you'd want as well.

2 Comments

This helped me greatly, as I was looking for an answer when applying a default fallback object when null-coalescing (??) through potential object sources. E.g.: const someData : SomeDataInterface = source1 ?? source2 ?? { /* Defaults */ } : SomeDataInterface
Tslint is the one saying the syntax is forbidden. Angle brackets is still very much a valid way of casting
7

You have accidentally caused yourself a problem with your interface declaration. It is a subtle one that you will come across with structurally typed languages.

interface IBase {
    height?:number;
    width?:number;
}

Because all of the properties are optional, the interface is essentially {}. i.e. any object satisfies this interface. That's too general to be useful in most cases.

For example, it is perfectly acceptable to do this:

var x: IBase = {
    a: 'efsdsdf',
    v: 'sdfdsf' 
};

I think you'll agree that really this object is not useful anywhere I wanted to use an IBase object.

With this out of the way, you may find the most graceful solution is to create an interface that matches your element definition.

interface IElement {
    base: {
        height?:number;
        width?:number;
    }
}

var element: IElement = {
    base: {
        height: 4
    }
}

1 Comment

Typescript may have improved this sine this post. Your example does give me an error: Type '{ a: string; v: string; }' is not assignable to type 'IBase'. Object literal may only specify known properties, and 'a' does not exist in type 'IBase'.(2322)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.