Shaun Luttin
Shaun Luttin

Reputation: 141642

Maintain type safety while expressing, "This object literal's values are all of type T."

Here is an example in which T is StringConstant.

type StringConstant =
    'fooValue' |
    'barValue' |
    'bazValue';

Attempt 01

We have tried casting each property in an object literal as StringConstant. The downside is that this approach does not type check the property values.

const StringConstant01 = {
    foo: 'fooValue' as StringConstant,
    bar: 'barValue' as StringConstant,
    baz: 'bazValue!!!' as StringConstant, // no error, bad
}

Though it does work with assignment to a constant of type T and catches errors when we use the wrong property key.

const x: StringConstant = StringConstant01.bar;
const y: StringConstant = StringConstant01.qux; // error, good

Attempt 02

We have tried using an index type.

type StringConstantMap = {
    [key: string]: StringConstant;
}

const StringConstant02: StringConstantMap = {
    foo: 'fooValue',
    bar: 'barValue',
    baz: 'bazValue!!!' // error, good
}

The downside is that we lose type info on the property keys.

const x: StringConstant = StringConstant02.bar;
const y: StringConstant = StringConstant02.qux; // no error, bad

Upvotes: 2

Views: 51

Answers (1)

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174407

Use an interface:

interface IStringConstants {
    foo: StringConstant;
    bar: StringConstant;
    baz: StringConstant;
}

const StringConstant01: IStringConstants = {
    foo: 'fooValue',
    bar: 'barValue'
    baz: 'bazValue!!!' // error
}

What you can't prevent is that 'bazValue!!!' as StringConstant will not result in a compiler error.

Upvotes: 3

Related Questions