2

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
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
  • I'm probably missing something. :-) If you need the property names checked, what's wrong with `interface Whatever { foo: StringConstant, bar: StringConstant };`? – T.J. Crowder Oct 18 '18 at 16:12
  • There is nothing wrong with that other than it not having occurred to me. I think was I was getting caught up in advanced types. It's also more repetition of property names that I would have liked. – Shaun Luttin Oct 18 '18 at 16:16
  • LOL - Sorry, I genuinely thought I was failing to get the point. :-) – T.J. Crowder Oct 18 '18 at 16:19

1 Answers1

3

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.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • If I am not mistaken, a type would be an additional alternative to an interface. `type StringConstantMap = { foo: StringConstant; bar: StringConstant; baz: StringConstant; }`. – Shaun Luttin Oct 18 '18 at 16:23
  • @ShaunLuttin: That's correct. For the trade-offs / differences, see e.g. here: https://stackoverflow.com/a/37233777/572644 – Daniel Hilgarth Oct 18 '18 at 16:25