I have an interface like this for example:
interface Account {
email: string;
enabled: boolean;
}
And I would like to create a method that returns a default value for these fields. So I have something like this:
function defaultValue(propName:string) {
if (propName === 'email') return '';
if (propName === 'enabled') return true;
}
It works well however if any property of Account
changes, the defautValue()
method would still compile even though it's now broken.
So I'm wondering if I can specify that propName
should have a type like property name of Account
? Or is there any other good pattern I can use to enforce type checking in that situation?
CodePudding user response:
You can use a function to assert the variable is never by the end of the if statements and keyof T
to get a union of keys:
function assertNever(v: never): never {
throw new Error("Should never happen!");
}
function defaultValue(propName:keyof Account) {
if (propName === 'email') return '';
if (propName === 'enabled') return true;
assertNever(propName);
}
You can also improve the caller experience by making the function generic, but this will mean some type assertions in the implementation.
function defaultValue<K extends keyof Account>(propName:K): Account[K] {
if (propName === 'email') return '' as Account[K];
if (propName === 'enabled') return true as Account[K];
assertNever(propName);
}
let email = defaultValue('email') // string
let enabled = defaultValue('enabled') // boolean
CodePudding user response:
You can do this by adding a more specific string type to the propName
parameter. Then, use a switch statement to have smart type inference that you are correctly returning a value that matches the return type for each possible branch in the function.
interface Account {
email: string;
enabled: boolean;
shouldError: boolean;
}
function defaultValue(propName: keyof Account): Account[keyof Account] { // shows error for not always returning value
switch (propName) {
case "email":
return "";
case "enabled":
return true;
// uncomment this code to fix the error
// case "shouldError":
// return true;
}
}