0

I am trying to type my action. Here is the code.

type Increment = {
  type: 'INCREMENT'
  payload: number
}

const action: Increment = {
  type: 'INCREMENT',
  payload: 1
}

console.log(action);

Then I wanted to extract 'INCREMENT' into its own variable so I can use it in multiple places. So I did this

const INCREMENT = 'INCREMENT'

type Increment = {
  type: INCREMENT
  payload: number
}

const action: Increment = {
  type: 'INCREMENT',
  payload: 1
}

console.log(action);

However the TS compiler is yelling at me and says

'INCREMENT' refers to a value, but is being used as a type here. Did you mean 'typeof INCREMENT'?

so I had to add typeof in front of INCREMENT to make it happy, as in

type Increment = {
  type: typeof INCREMENT
  payload: number
}

I don't understand why is that when I am using a variable to reference the string suddenly the breaks the rule. Also shouldn't typeof INCREMENT be a string string. I thought it would be equivalent to type: string but apparently here I cannot assign type with anything string other than INCREMENT. Can someone explain this to me?

0

3 Answers 3

1

In your first example, you were using a TypeScript feature called literal types which allow you to specify the exact value a string type variable can have. In this case the property type can only have the string value INCREMENT.

type Increment = {
  type: 'INCREMENT'
  payload: number
}

When you assigned that string literal to a variable using const, TypeScript no longer recognizes it as a type but as an actual value. Hence the error message 'INCREMENT' refers to a value....

If you assign that literal to a type variable that would work, as TypeScipt will see that as a type and not a value.

type INCREMENT = 'INCREMENT';
type Increment = {
  type: INCREMENT
  payload: number
};

However, you won't be able to "reuse" the actual string literal as a value it in multiple places.

One other solution I would recommend is using string enums. For example:

enum IncrementType {
  INCREMENT = 'INCREMENT',
  DECREMENT = 'DECREMENT' // Added this just as an example
}

type Increment = {
  type: IncrementTypes
  payload: number
}

const action: Increment = {
  type: IncrementType.INCREMENT,
  payload: 1
};
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the answer! I remember in JS typeof INCREMENT would just return string. but in TS it would return the actual exact value a string has i.e. 'INCREMENT'?
No worries. As far as I'm aware of, the typeof operator behaves the same way in TS as it does in JS.
then in that case. should typeof always returns string instead of the specific exact value?
@Joji Yes, I believe that typeof will always return string. The TS docs say this about typeof: "These typeof type guards are recognized in two different forms: typeof v === typename and typeof v !== typename, where typename must be number, string, boolean, or symbol." typescriptlang.org/docs/handbook/…
0

Try this: instead of const define new type

type INCREMENT = 'INCREMENT'

type Increment = {
  type: INCREMENT
  payload: number
}

const action: Increment = {
  type: 'INCREMENT',
  payload: 1
}

console.log(action);

Comments

0

It's because with const INCREMENT = 'INCREMENT' you have a string value but you're using it to declare a type. That's why typeof INCREMENT works; that's a string literal so you get type: "INCREMENT" which is like a sub-type of string (it is-a string). However, it can only have a single value of "INCREMENT". Like so:

const INCREMENT = 'INCREMENT'; // the apparent type is 'INCREMENT'
console.log(typeof INCREMENT); // the actual type is string

type Increment = {
  type: typeof INCREMENT,
  payload: number
}

const action: Increment = {
  type: INCREMENT,
  payload: 1
}
console.log(typeof action.type); // string
console.log(action.type); // INCREMENT

If you want use something like that in more than one place and will likely have more than one type. You can try an enum.

enum Type {
    INCREMENT = "INCREMENT",
    FOO = "FOO"
}

type Increment = {
  type: Type
  payload: number
}

const action: Increment = {
  type: Type.INCREMENT,
  payload: 1
}

console.log(action.type); // INCREMENT

2 Comments

"That's why typeof INCREMENT works; that's string so you get type: string." this is NOT true and this is exactly what I said in the question. If we were to get type: string as you said, we can assign any string to type later, but in fact we can only assign "INCREMENT" to it, not any other string value.
It actually is true tho I'll agree I did not clarify it enough; see the edits. @Joji

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.