Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
660 views
in Technique[技术] by (71.8m points)

casting - Typescript: Index signature is missing in type

I want MyInterface.dic to be like a dictionary name: value, I define it as follows:

interface MyInterface {
    dic: { [name: string]: number }
}

Now I create a function which waits for my type:

function foo(a: MyInterface) {
    ...
}

And the input:

let o = {
    dic: {
        'a': 3,
        'b': 5
    }
}

I'm expecting foo(o) to be correct, but the compiler is falling:

foo(o) // Typescript error: Index signature is missing in type { 'a': number, 'b': number }

I know there is a possible casting: let o: MyInterface = { ... } which do the trick but the question is, why typescript is not recognizing my type?


Extra: works fine if o is declared inline:

foo({ 
  dic: {
    'a': 3, 
    'b': 5
  }
})
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem is that when the type is inferred, then the type of o is:

{ dic: { a: number, b: number } }

That's not the same as { dic: { [name: string]: number } }. Critically, with the top signature you're not allowed to do something like o.dic['x'] = 1. With the 2nd signature you are.

They are equivalent types at runtime (indeed, they're the exact same value), but a big part of TypeScript's safety comes from the fact that these aren't the same, and that it'll only let you treat an object as a dictionary if it knows it's explicitly intended as one. This is what stops you accidentally reading and writing totally non-existent properties on objects.

The solution is to ensure TypeScript knows that it's intended as a dictionary. That means:

  • Explicitly providing a type somewhere that tells it it's a dictionary:

    let o: MyInterface

  • Asserting it to be a dictionary inline:

    let o = { dic: <{ [name: string]: number }> { 'a': 1, 'b': 2 } }

  • Ensuring it's the initial type that TypeScript infers for you:

    foo({ dic: { 'a': 1, 'b': 2 } })

If there's a case where TypeScript thinks it's a normal object with just two properties, and then you try to use it later as a dictionary, it'll be unhappy.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...