简体   繁体   中英

How can I type a typescript interface property using a predefined object?

  • I have a typescript interface called Customer.
  • I want one property of that interface, orderAuthorizationStatus, to be only one of three strings: 'unauthorized', 'waitingForAuthorization' or 'authorized'
  • At the same time I want to store these three strings somewhere, so I can use them for comparisons, translations etc., and not change them 10 different times should I decide to change the wording.
  • I want to use the stored strings, for typing my interface property, I currently have this solution:
export const OrderAuthorizationStates = {
  unauthorized: "unauthorized",
  waitingForAuthorization: "waitingForAuthorization",
  authorized: "authorized"
}

export interface Customer {
  id: number;
  name: string;
  orderAuthorizationStatus: "unauthorized" | "waitingForAuthorization" | "authorized"
}

This works and gives me the errors i want:

let customer: Customer;

if (customer.orderAuthorizationStatus === 'asdf') {
 somecode
}

Error: "This condition will always return 'false' since the types '"unauthorized" | "waitingForAuthorization" | "authorized"' and '"asdf"' have no overlap"
I can also use it like this:

let customer: Customer;

if (customer.orderAuthorizationStatus === OrderAuthorizationStates.authorized) {
 somecode
}

What I cannot solve is, how to use the objectproperties of my OrderAuthorizationStates object to type the interfaceproperty of my customer interface:

export interface Customer {
  id: number;
  name: string;
  orderAuthorizationStatus: OrderAuthorizationStates.unauthorized | OrderAuthorizationStates.waitingforAuthorization | OrderAuthorizationStates.authorized
}

Error: Cannot find namespace 'OrderAuthorizationStates'

Help would be much appreciated!

String enums do almost exactly what you want:

enum OrderAuthorizationStates {
    Unauthorized = "Unauthorized",
    WaitingForAuthorization = "WaitingForAuthorization",
    Authorized = "Authorized"
}

interface Customer {
    id: number;
    name: string;
    orderAuthorizationStatus: OrderAuthorizationStates;
}

let customer: Customer = { id: 1, name: "RichN", orderAuthorizationStatus: OrderAuthorizationStates.Unauthorized};
if (customer.orderAuthorizationStatus === "Unauthorized") {
    console.log("Customer is unauthorized");
}

// Authorize it!
customer.orderAuthorizationStatus = OrderAuthorizationStates.Authorized;

if (customer.orderAuthorizationStatus === OrderAuthorizationStates.Authorized) {
    console.log("Customer is now authorized");
}

// Output:
// Customer is unauthorized
// Customer is now authorized

In addition, if you do if (customer.orderAuthorizationStatus === 'asdf') you get the error 'This condition will always return 'false' since the types 'OrderAuthorizationStates' and '"asdf"' have no overlap.', which is what you want.

Found a way without using enum.

Create a type that is inferred from the object:

export const OrderAuthorizationStatuses = {
    unauthorized: 'unauthorized',
    waitingForAuthorization: 'waitingForAuthorization',
    authorized: 'authorized'
}

type OrderAuthorizationStatus = typeof OrderAuthorizationStatuses[keyof typeof OrderAuthorizationStatuses]

Now you can use the object keys as variables throughout your application, without any type missunderstandings with enum.member and you can use all the object methods on it, plus you can use it to type your interface properties, or anything really:

export interface Customer {
  id: number;
  name: string;
  orderAuthorizationStatus: OrderAuthorizationStatus
}

source

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM