19

How to force a proper second argument type for the createMessage method here:

const EMAIL_TEMPLATES = {
  DOCTOR_SIGNUP: DoctorSignupOutput,
  CHANGE_PASSWORD: PasswordParams
} as const;

@Injectable()
export class EmailService {

  sendEmail() {
    console.log('Email sent!');
  }

  createMessage(template: keyof typeof EMAIL_TEMPLATES, params: ?) {

  }


}

so i.e. only objects of type DoctorSignupOutput are allowed, when template equals DOCTOR_SIGNUP?

1 Answer 1

39

try like that

  createMessage<
    T extends keyof typeof EMAIL_TEMPLATES, // <- T points to a key
    R extends (typeof EMAIL_TEMPLATES)[T] // <- R points to the type of that key
  >(template: T, params: R) {

  }

A detailed example:

interface MyInterface { 
    keyString: string;
    keyNumber: number;
}

function createMessage<
  O extends object, // object itself
  K extends keyof O, // all its keys
  V extends O[K] // types of keys, once K is specified, it's narrowed to related type.
>(object: O, key: K, value: V) {
    console.log(object, key, value);
}

const data: MyInterface = {
    keyString: 'hello',
    keyNumber: 777,
};

createMessage(data, 'keyString', 'world'); // works
createMessage(data, 'keyNumber', 42); // works

createMessage(data, 'keyString', 42); // fails due to wrong type
createMessage(data, 'keyNumber', 'world'); // fails due to wrong type
createMessage(data, 'keyUnknown', 'random'); // fails due to missed key in the original interface.

Playground

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

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.