59

I am using the following type in my TypScript:

interface ExerciseData {
    id : number;
    name : string;
    vocabulary : {
        from : string;
        to : string;
    }[];
}

Now I'd like to create a variable that is of the same type as the attribute vocabulary, trying the following:

var vocabs : ExerciseData.vocabulary[];

But that is not working. Is it possible to reference to a subtype somehow? Or would I have to do something like this?

interface ExerciseData {
    id : number;
    name : string;
    vocabulary : Vocabulary[];
}

interface Vocabulary {
        from : string;
        to : string;
}

var vocabs : Vocabulary[];

Thanks a lot for hints.

3
  • You are correct. You should do what you did in the last code block. Commented Jan 10, 2015 at 11:42
  • Thank you @WayneEllery - so you would say this is definitely not possible? Commented Jan 10, 2015 at 12:07
  • Yeah. You should really declare your types anyway. Commented Jan 10, 2015 at 12:11

4 Answers 4

123

You can reference interface subtypes using lookup types, added in TypeScript 2.1:

interface ExerciseData {
    id: number;
    name: string;
    vocabulary: Array<{
        from: string;
        to: string;
    }>;
}

type Name = ExerciseData['name']; // string

These lookup types can also be chained. So to get the type of a vocabulary item you can do this:

type Vocabulary = ExerciseData['vocabulary'][number]; // { from: string; to: string; }

Or with even more chaining, the from field:

type From = ExerciseData['vocabulary'][number]['from']; // string

For complex scenarios it's also possible to base the lookup type on another type. For example, on a string literal union type:

type Key = 'id' | 'name';
type FieldTypes = ExerciseData[Key]; // number | string
Sign up to request clarification or add additional context in comments.

4 Comments

Any way of do this dinamically? Like in JS ExerciseData[xxx][]
How about if you want to access a child of vocabulary, can thus be chained?
@xperiments I have added an example of basing the lookup type on another type. If with dynamically you actually meant using a string value, then no, it wouldn't be possible because the TypeScript compiler cannot know what that value will be in runtime.
@Buts Yes, this is possible. I've added an example in my answer.
8

I found it's working in the next way these days:

interface User {
  avatar: string;
}

interface UserData {
  someAvatar: User['avatar'];
}

very useful if you don't want to export all the things.

Comments

8

Something to keep in mind if you are trying to access by Interface['index'], but index is possibly undefined (optional).

Note the vocabulary? below:

interface ExerciseData {
    id: number;
    name: string;
    vocabulary?: {
        from: string;
        to: string;
    }[];
}

Use the NonNullable utility type like so...

type Test = {
    prop: NonNullable<ExerciseData['vocabulary']>[number]['from']
}

Comments

7

Not exactly what you want but you can hack around this with the typof keyword but only if you have a var that is declared as your interface type like below. Note that I think what you did in your last codeblock is a lot better :)

interface ExerciseData {
    id : number;
    name : string;
    vocabulary : {
        from : string;
        to : string;
    }[];
}
var x: ExerciseData;
var vocabs : typeof x.vocabulary[];

1 Comment

Hmmm, that's a quite interesting possibility indeed - though not quite what I was looking for. Thank you for mentioning it.

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.