iffy
iffy

Reputation: 729

Typescript: Property 'x' is missing in type '{}' for computed key

This piece of Typescript:

enum Field {
    age,
    bugs,
}
interface Foo {
    number_age: number;
    number_bugs: number;
}

function makeFoo():Foo {
    let ret = {};
    let i = 0;
    for (let key in Field) {
        ret['number_'+key] = i++;
    }
    return ret;
}

throws this error when compiling:

$ tsc test.ts 
test.ts(16,5): error TS2322: Type '{}' is not assignable to type 'Foo'.
  Property 'number_age' is missing in type '{}'.

But ret will definitely have a number_age property at runtime. How do I either trick the compiler into knowing that number_age and number_bugs will be there or otherwise change my code so that it compiles?

Upvotes: 1

Views: 2124

Answers (3)

rpadovani
rpadovani

Reputation: 7360

You can define that ret will be a Foo element using the keyword as

enum Field {
    age,
    bugs,
}
interface Foo {
    number_age: number;
    number_bugs: number;
}

function makeFoo():Foo {
    let ret = {} as Foo;
    let i = 0;
    for (let key in Field) {
        ret['number_'+key] = i++;
    }
    return ret;
}

Read the documentation about type assertions:

Sometimes you’ll end up in a situation where you’ll know more about a value than TypeScript does. Usually this will happen when you know the type of some entity could be more specific than its current type.

Type assertions are a way to tell the compiler “trust me, I know what I’m doing.” A type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler. TypeScript assumes that you, the programmer, have performed any special checks that you need.

Type assertions have two forms. One is the “angle-bracket” syntax:

let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;

And the other is the as-syntax:

let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;

The two samples are equivalent. Using one over the other is mostly a choice of preference; however, when using TypeScript with JSX, only as-style assertions are allowed.

Upvotes: 2

Siamand
Siamand

Reputation: 1080

you should use casting operator <TYPE>

enum Field {
    age,
    bugs,
}
interface Foo {
    number_age: number;
    number_bugs: number;
}

function makeFoo():Foo {
    let ret = {};
    let i = 0;
    for (let key in Field) {
        ret['number_'+key] = i++;
    }
    return <Foo>ret; // Here 
}

Upvotes: 0

Ryan Cavanaugh
Ryan Cavanaugh

Reputation: 221302

You're pretty far off the rails here (you're going to also make number_0 and number_1 properties on Foo, is this intended?) so it's going to be more work than its worth to "properly" typecheck this code. Just use any:

function makeFoo():Foo {
    let ret: any = {};
    let i = 0;
    for (let key in Field) {
        ret['number_'+key] = i++;
    }
    return ret;
}

Upvotes: 0

Related Questions