my codes:
export const LOAD_USERS = 'LOAD_USERS';
export const CREATE_USER = 'CREATE_USER';
export interface ACTION {
type: string,
payload: any
}
I want to restrict the ACTION.type to be either 'LOAD_USERS' or 'CREATE_USERS'.
I can do this by String Literal type: 'LOAD_USERS'|'CREATE_USERS'
. But can not do it with variables type: LOAD_USERS | CREATE_USERS
. My editor prompts "can not find name 'LOAD_USERS'".
Is there a way to use variables to do this? There could be typo when typing the same string in more than one place.
Hence, you can treat a variable that has a string literal type like a variable of type string . You can access properties, call methods, and use operators, just as you would with regular strings: const eventName: "click" | "mouseover" = "click"; eventName. length; // 5 eventName.
A string literal is where you specify the contents of a string in a program. Here 'A string' is a string literal. The variable a is a string variable, or, better put in Python, a variable that points to a string.
A string literal is a sequence of zero or more characters enclosed within single quotation marks. The following are examples of string literals: 'Hello, world!' 'He said, "Take it or leave it."'
There are three sets of literal types available in TypeScript today: strings, numbers, and booleans; by using literal types you can allow an exact value which a string, number, or boolean must have.
You can use the typeof
operator, it returns the inferred type:
export const LOAD_USERS = 'LOAD_USERS';
export const CREATE_USER = 'CREATE_USER';
export interface ACTION {
type: typeof LOAD_USERS | typeof CREATE_USER,
payload: any
}
If you want to ensure that the string in your variables will be the action type, then you should use a type alias and explicitly type the variables with that type:
export type ActionNames = 'LOAD_USERS' | 'CREATE_USER';
export const LOAD_USERS: ActionNames = 'LOAD_USERS';
export const CREATE_USER: ActionNames = 'CREATE_USER';
export interface ACTION {
type: ActionNames;
payload: any;
}
If the strings in the variables don't match one of the strings in ActionTypes
, then you'll get an error, which is desired to prevent mistakes. For example, this would error:
export type ActionNames = 'LOAD_USERS' | 'CREATE_USER';
export const LOAD_USERS: ActionNames = 'LOAD_USERS_TYPO'; // error, good
Update
Note that in newer versions of TypeScript the following is another option:
const actionNames = ['LOAD_USERS', 'CREATE_USER'] as const;
type ActionNames = typeof actionNames[number]; // typed as 'LOAD_USERS' | 'CREATE_USER'
Also, looking back on this question, you probably want to declare your actions with a common string literal type property that's differentiated by the string literal type (see discriminated unions).
For example:
interface LoadUsersAction {
type: "LOAD_USERS";
}
interface CreateUserAction {
type: "CREATE_USER";
name: string;
// etc...
}
type Actions = LoadUsersAction | CreateUserAction;
Also, I recommend not bothering with the variables. Using the strings directly is type safe.
Since TypeScript 2.4 you can use enums with string members. Enums define a set of named constants.
export enum UserActions{
LOAD_USERS = "LOAD_USERS",
CREATE_USER = "CREATE_USER"
}
export interface ACTION {
type: UserActions,
payload: any
}
You cannot totally eliminate the duplication, but you can reduce it to the bare minimum:
type nameIt = 'LOAD_USERS' | 'CREATE_USERS'
export const LOAD_USERS = 'LOAD_USERS';
export const CREATE_USER = 'CREATE_USER';
This allows you to use the nameIt
type elsewhere, but it does mean repeating the strings in your constants and in the type.
Alternatively, if you are writing a new piece of code, you might prefer to use an enum
.
Simplifying the existing answers further,
export type ActionTypes = 'LOAD_USERS' | 'CREATE_USER';
is sufficient by itself. To refer to a specific action type, just use the quoted string literal:
'LOAD_USERS'
In some other languages we avoid repeating such string literals and prefer to name them with a declaration. But that's because those other languages don't have string literal types! In TypeScript, 'LOAD_USERS'
already is a compile-time name for a statically-checkable type. You don't necessarily need to give it another name.
Example:
declare function doAction(action: ActionTypes);
doAction('LOAD_USERS'); // okay
doAction('LOAD_USES'); // error: typo is caught by compiler
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With