Home > Mobile >  how to preserve keys when using typeof on index signature?
how to preserve keys when using typeof on index signature?

Time:07-18

I'm trying to preserve the properties of an object that declares its type via index signature. Minimal example below (the code snipped doesn't do anything useful and isn't subject to the question, I want to use mapped types over these, but also retain compiler support for the body, for example a function accepting indexWithType and outputting a mapped type while preserving its keys).

I understand why this is happening, with the type, typeof resolves to IndexSignature and discards the specific subtype.

How do I convince typescript to use the lower bound instead?

type IndexSignature = {
    [index: string]: string
}

const indexWithType: IndexSignature = {
    test: "value"
}

const indexWithOutType = {
    test: "value"
}

const lost: typeof indexWithType = {
    // NOT AN ERROR! But I want one, typescript lost the properties of indexWithType
}

const notLost: typeof indexWithOutType = {
    // ERROR! Does work as expected.
}

CodePudding user response:

By declaring lost as having type IndexSignature, you lose the type of the keys. There is currently no way to ‘undo’ this type annotation and retrieve the original type.

To ensure that an object satisfies IndexSignature while still retaining the type of the keys, you do something like this:

const checkIsIndexSignature = (_: IndexSignature) => {}

const good = {
    test: "value"
}
// no type errors
checkIsIndexSignature(good)

const bad = {
    test: 42
}
// Argument of type '{ test: number; }' is not assignable to parameter of type 'IndexSignature'.
checkIsIndexSignature(bad)

Alternatively, you could do something like

const indexSignature = <T extends IndexSignature>(x: T): T => x
// good has type {test: "value"}
const good = indexSignature({test: "value"})
// type error
const bad = indexSignature({test: 42})

There is currently a proposal for a satisfies operator that would allow you to do

const good = {
    test: "value"
} satisfies IndexSignature

This scenario is explored more in the ‘Property Value Conformance’ section of that issue.

  • Related