Home > Blockchain >  Typescript: Start with one type but end up with another type after declaring the object
Typescript: Start with one type but end up with another type after declaring the object

Time:08-26

Sorry for not knowing the exact TS terms for this. But how do I achieve this behavior:

type LocaleErrorMessages = {
    required?: () => string | string
    email?: () => string | string
    passwords?: () => string | string
}

const DanishErrorMessages: LocaleErrorMessages = {
    email: () => 'Tjek om du har skrevet din e-mail korrekt',
    passwords: () => "Kodeordet lever ikke op til kravene"
}


DanishErrorMessages.email() // do NOT want this to Error
DanishErrorMessages.required() //  want this to Error

Playground link here.

CodePudding user response:

use generics

LocaleErrorMessages<T extends object> = {
  [k in keyof T]?: Func | string
) 
   

CodePudding user response:

DanishErrorMessages has type LocaleErrorMessages. Therefore, when you try to call its' methods, signatures from LocaleErrorMessages are being used. It means that every of your methods might be undefined. Here's how I solved your problem.

type LocaleErrorMessages = {
    required?: () => string | string
    email?: () => string | string
    passwords?: () => string | string
}

type DanishErrorMessages = LocaleErrorMessages & {
    email: () => string | string
    passwords: () => string | string
}

const d : DanishErrorMessages = {
    email: () => 'Tjek om du har skrevet din e-mail korrekt',
    passwords: () => "Kodeordet lever ikke op til kravene"}


d.email() // no error
d.required() //  errors

Basically, any variable of type LocaleErrorMessages could only be used with null checks:

const EnglishErrorMessages : LocaleErrorMessages = {email:..., passwords: ...}

if (EnglishErrorMessages.email !== undefined) {
  EnglishErrorMessages.email()
}

Try to think how are you goind to use your LocaleErrorMessages variables. If you have way some ts code that uses these methods to retrieve string and generate HTML code, how does it know that this exact locale has defined required field?

const userLanguageLocale : LocaleErrorMessages = getUserLanguageLocale()

const alertDiv = document.createElement('div')
alertDiv.textContent = userLanguageLocale.required() // compilation error

Therefore, LocaleErrorMessages type is probably useless with this approach. But with null check it makes more sense, since you can change behavior of your page depending on presence of some locales:

const userLanguageLocale : LocaleErrorMessages = getUserLanguageLocale()

const alertDiv = document.createElement('div')
if(userLanguageLocale.required !== undefined) { // if this locale is available
    alertDiv.textContent = userLanguageLocale.required() // no compilation error
}

CodePudding user response:

If you have a specific situation you may be able to use Omit and Required.

See the Utility Types

CodePudding user response:

As far as I understand what you're trying to achieve, you should rather make an interface - ILocaleErrorMessages that defines what method should be on the object.

DanishErrorMessages can be a class that implements interface. But throughout the application, you can use interface as a method/variable signature, but pass proper local language instance.

interface ILocaleErrorMessages {
    required?: () => string;
    email?: () => string;
    passwords?: () => string;
}

class DanishErrorMessages implements ILocaleErrorMessages {
    email() { return 'Tjek om du har skrevet din e-mail korrekt'};
    passwords() {return "Kodeordet lever ikke op til kravene" };
}

const localErrorMessages: ILocaleErrorMessages = new DanishErrorMessages();

// method `required()` is undefined, but does not break any code
const requiredMessage = localErrorMessages.required?.(); 
console.log("required message: ", requiredMessage);

const emailMessage = localErrorMessages.email?.();
console.log("email message: ", emailMessage);

const passwordMessage = localErrorMessages.passwords?.();
console.log("password message: ", passwordMessage);

Also, for the cases where function that returns message is undefined, you can use optional chaining operator?. - func?.();

TypeScript playground link here.

  • Related