1

barOrBaz value should be restricted to foo constant keys:

const foo = {
  BAR: 'BAR',
  BAZ: 'BAZ'
};

let barOrBaz: keyof typeof foo; // type: "BAR" | "BAZ"
const BAR = 'BAR';

barOrBaz = BAR; // ok
barOrBaz = 'BAZ'; // ok
barOrBaz = foo.BAR; // Type 'string' is not assignable to type '"BAR" | "BAZ"

The problem is that when barOrBaz is assigned to foo.BAR (which is the usual way how foo is used), it triggers an error:

Type 'string' is not assignable to type '"BAR" | "BAZ"

Why is foo.BAR interpreted as string and not "BAR" string type?

How can this be fixed? Are there other ways to implement this?

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Possible duplicate of [How can I hint to the Typescript compiler to infer string literal types for properties?](https://stackoverflow.com/questions/47606183/how-can-i-hint-to-the-typescript-compiler-to-infer-string-literal-types-for-prop) – artem Feb 06 '18 at 13:51
  • @artem Thanks, it's not a dupe but related question. Considering that the goal is specific, the solution may be specific too (as the answer shows). – Estus Flask Feb 06 '18 at 14:29

1 Answers1

1

For constants the type of the constant becomes the string literal type, for objects literals the field is inferred to be string. This issue mentions this problem and the reasoning is:

It's correct behavior because I may update n0.A = 'B' and I don't expect to see an error that type 'A' is not compatible with 'B'

So basically you could do foo.BAR = 'baz' even in foo is a constant

You could force the type to the literal type but as the above example shows it's not really safe if the object is visible from javascript (typescript will not allow the assignment above):

const foo = {
    BAR: 'BAR' as 'BAR',
    BAZ: 'BAZ' as 'BAZ'
};
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357