I want to set a type for an object and I want to set it to any of the variables values inside types.ts
:
export const INIT = "INIT";
export const LOGIN = "LOGIN";
I want to say the type can be any of the variables values in the types.ts
:
import { LOGIN, INIT } from "./types";
interface Action {
type: typeof INIT | typeof LOGIN;
}
export const reducer = (state = initialState, action: Action) => {
switch (action.type) {
case LOGIN:
return {
state,
};
}
};
Is there anyway I can tell typescript to map all the constant variables inside types.ts
and set all of their values as a type at once and not setting typeof each of them everytime a new constant I add in the types.ts
?
CodePudding user response:
You can accomplish this by using a namespace import statement for all of your exported constant values. See comments in the code below:
./constants.ts
:
export const INIT = 'INIT';
export const LOGIN = 'LOGIN';
./module.ts
:
/* Using a namespace import statement places all of the exports from
the './constants.ts' module on an object named `Constant`: */
import * as Constant from './constants';
/** A type utility to get a union of all types of values in an object type */
type Values<T> = T[keyof T];
/* This uses the same identifer as the imported value object Constant.
Because it's a type name, using the same name is ok — TS has no problems and it
makes the `Constant` identifier work like a string enum
in the scope of this module: */
type Constant = Values<typeof Constant>;
//^? type Constant = "INIT" | "LOGIN"
type Action = {
type: Constant;
//^? (property) type: "INIT" | "LOGIN"
};
/* You didn't show the initialState variable in your question, so here's
an example: */
type State = Record<'prop1' | 'prop2', string>;
//^? type State = { prop1: string; prop2: string; }
const initialState: State = {
prop1: 'hello',
prop2: 'world',
};
const reducer = (state = initialState, action: Action) => {
switch (action.type) {
case Constant.LOGIN: return { state };
// etc...
}
};
Although a more modular pattern would be to do that in the constants module instead:
./constants.ts
:
export const INIT = 'INIT';
export const LOGIN = 'LOGIN';
export const Constant = {
INIT,
LOGIN,
} as const;
type Values<T> = T[keyof T];
export type Constant = Values<typeof Constant>;
./module.ts
:
import {Constant} from './constants';
type Action = {
type: Constant;
//^? (property) type: "INIT" | "LOGIN"
};
// ... the remaining code is the same as the above example