1

I have this constant declaration:

export const Actions = {
    VIEW: 'view',
    EDIT: 'edit',
};

and lets assume now I have a function like below:

// how to ensure action variable below is string of value either view or edit
function insertAction(action: string): void {
  console.log('trust me i inserted the action');
}

My goal is to allow action parameter to have values only view | edit and understand this *dynamically, so please do not suggest using union solution because I know that already and is not fit to my purpose.

I have tried signature like the one below

function insertAction(action: typeof Actions[keyof typeof Actions]

but it does not work.

I can still call the function insertAction('whatever') and ts compile does not fail neither the linter.

In my package.json am using typescript version 4.4.2 with PHPStorm Editor and nextjs

    "typescript": "^4.4.2"
2
  • 1
    typeof Actions[keyof typeof Actions] should work if you declare Actions with the as const modifier. Eg: export const actions = {...} as const;. Can you let us know if that works? Commented Jun 1, 2022 at 16:30
  • @CRice thank you that worked!!! ibb.co/vZmMs2n I will read more about the as const typescript syntax was not aware of it. Without as const this was not working. Also am open to any solution if there are more elegant ones although this achieves now what I intend to and am happy Commented Jun 1, 2022 at 16:34

2 Answers 2

3

why not use enum and assign action:EAction?

That should look like this:

export enum EActions {
    VIEW = 'view',
    EDIT = 'edit',
}

your function

function insertAction(action: EAction): void {
  console.log('trust me i inserted the action');
}

will show you type error:

insertAction('whatever'); // will show you error

Argument of type '"whatever"' is not assignable to parameter of type 'EAction'.

Use your EActions:

insertAction(EAction.VIEW);

It would be easier to read in my opinion.

Example: JS Playground

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

4 Comments

That was my first idea, I like it. I see the other way with as const syntax, but I don't really like the whole typeof stuff, maybe because I don't use it very often.
Thanks this look more elegant as you entioned avoids "typeof keyof" long syntax. Iwill test it out in playground,. If the value of Eaction.VIEW is view instead of enum int than is perfect alternative to the other solution with as const. Upvoted thanks
@KristiJorgji glad it was helpful for you , if that answer your need I appreciate if you mark this as answer.
I tested now and works as expected. 1. I cannot use a different value 2. the value of Eaction.VIEW is the string on right side of = so 'view' . Both are valid. Thank you chose your answer as solution considering is slightly more elegant than the as const one and using typeof TYPE [keyof tyopeof TYPE]
2

Your current solution:

function insertAction(action: typeof Actions[keyof typeof Actions])

should work, as long as you declare the Actions object using the as const modifier:

export const Actions = {
    VIEW: 'view',
    EDIT: 'edit',
} as const; // <-- note the assertion here.

This works because by default, when you declare an object without an explicit type, eg:

export const Actions = {
    VIEW: 'view',
    EDIT: 'edit',
}

TypeScript can see that the variable is constant, and cannot be reassigned. However since it is assigned an object with potentially mutable values, TypeScript will infer for that object the type:

{
  VIEW: string;
  EDIT: string;
}

What you want is for the value type not to be string, but the exact literal string type for "view" and "edit". Using the as const modifier informs TypeScript that the values of the object will not be mutated, and so it will then infer the stricter, literal string type for those values.

Then, since the value types are the exact strings "view" and "edit" respectively, using typeof Actions[keyof typeof Actions] will produce the union type "view" | "edit", exactly what is needed for your parameter type.

Comments

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.