3

I am trying to create a constant which can only have two values as shown in code. And state.lang is already type-safe as en | ar.

const keyname: 'owner_name_en' | 'owner_name_ar' = 'owner_name_' + state.lang;

I am getting error like: Type 'string' is not assignable to type '"owner_name_en" | "owner_name_ar"'

How can I fix this error?

3
  • 1
    Calvin's dupe will answer your question practically, but the reason is that you are declaring a new type (as a string enum) with 'owner_name_en' | 'owner_name_ar'. You can't concatenate different types this way any more than you could do this valid: boolean = "tr" + "ue" hoping to get boolean <true>, because the right-hand side of the assignment is also two <string> in your case. Commented Jul 25, 2019 at 17:41
  • @msanford so how can i fix this? Commented Jul 25, 2019 at 17:44
  • @msanford state.lang is already type-safe as : 'en' | 'ar' Commented Jul 25, 2019 at 17:54

1 Answer 1

4

The reason is that you are declaring a new inline type (as a string enum) whose only possible values are 'owner_name_en' | 'owner_name_ar' (and null).

It is equivalent to

type OwnerNameLang = 'owner_name_en' | 'owner_name_ar';
const keyname: OwnerNameLang  = 'owner_name_' + state.lang;

Now, you can't concatenate different types this way any more than you could do this

const str: "hello" = "hel" + "lo"

hoping to get the unnamed inline type whose only possible values are null and "hello" (because the right-hand side of the assignment is also two <string> in your case).

You need to use type assertion, like

type OwnerNameLang = 'owner_name_en' | 'owner_name_ar';
const keyname: OwnerNameLang  = ('owner_name_' + state.lang) as OwnerNameLang ;

At this point, it may be preferable to use an an object with multiple decomposable properties (so that you can only store the en/ar as a string enum, and generate that string some other way). But without knowing more about the purpose of this string, it's hard to suggest a better alternative.

I'll add that I am a very strong supporter of type-safety, largely because it helps the developer notice when they, one day, discover a new state.lang and forget to handle it everywhere. Sometimes, though, a string is enough. Up to you to decide.

Sign up to request clarification or add additional context in comments.

5 Comments

That removes the error. But another question, state.lang is also typed as 'en' | 'ar'. This way, shouldn't typescript know what this concatenation will result in ?
@ashfaq.p In an ideal world, sure. But compilers can only be so smart. And the typescript will not currently manipulate strings as part of its type checking. To cover all edge cases of that would be quite an undertaking.
@msanford const valid: boolean = "tr" + "ue" isn't quite the right analogy, since it would be a totally invalid assignment at runtime. More like const str: "hello" = "hel" + "lo" which still isn't allowed in typescript.
@AlexWayne Quite right: I struggled to find a analogy quickly but I prefer yours.
@ashfaq.p To elaborate: you are a human being and know that what concatenation should look like, but a type checker does not, because an <OwnerNameLang> and <string> are not the same type, TS doesn't know how they should interact with one another. A type system is simply an implementation of sets with abstract in rules formal logic. This becomes more obvious (and powerful) with type generics. The point of the type checker is to err on the safe side.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.