sunknudsen
sunknudsen

Reputation: 7240

How to fix "Index signature is missing in type" error?

How can I fix the following type error?

Argument of type 'Query' is not assignable to parameter of type 'Input'. Index signature is missing in type 'Query'.(2345)

I am using the Input type as a generic type (catch-all) for query strings. When I feed an input of type Query, the error is thrown but the underlying JavaScript code runs just fine.

TypeScript Playground

interface Query {
    lorem: "0" | "1"
    ipsum: string
}

const query: Query = {
    lorem: "0",
    ipsum: "Hello world"
}

interface Input {
    [key: string]: string
}

const test = (input: Input) => {
    return input["lorem"]
}

test(query)

Upvotes: 15

Views: 19737

Answers (1)

Terry
Terry

Reputation: 66103

Solution 1: Use type instead of interface

That is because the type [key: string]: string is not compatible with your Query interface, the latter of which contains two allowed keys: lorem and ipsum, while the former contains any arbitrary string as key. This is an issue with TypeScript interfaces in general: a specific interface cannot be saved into a more generic interface.

However, a specific type can be saved into a more generic type, so a quick solution will be to simply convert your interface to types:

type Query = {
    lorem: "0" | "1"
    ipsum: string
}

const query: Query = {
    lorem: "0",
    ipsum: "Hello world"
}

type Input = {
    [key: string]: string
}

const test = (input: Input) => {
    return input["lorem"]
}

test(query)

Solution 2: Spread the variable when calling test()

An alternative solution will simply to keep the interfaces, but use ES6 object spread to deconstruct/spread the variable query before passing it into test(). By doing that, you will force TypeScript to recognize { ...query } as indexable.

This solution is smart but a bit hack-ish, because you have to probably add a comment in the code to explain why you can't just use test(query) instead of test({ ...query }):

interface Query {
    lorem: "0" | "1"
    ipsum: string
}

const query: Query = {
    lorem: "0",
    ipsum: "Hello world"
}

interface Input {
    [key: string]: string
}

const test = (input: Input) => {
    return input["lorem"]
}

test({ ...query })

There is an extended thread on discussion on TypeScript's GitHub repo: might be a good place to read a little more about it.

Upvotes: 56

Related Questions