I have an enum of possible values for the first parameter and I want the second parameter to be based on the first parameter. So, if NAME is given I want the second parameter to be as string. If AGE is given, I want the second parameter to be a number.
How can I do something like this?
enum KeyType {
NAME,
AGE
}
class MyClass {
public static setProperty(key: KeyType.NAME, value: string): void { }
public static setProperty(key: KeyType.AGE, value: number): void { }
}
And I would want to call the method like this:
MyClass.setProperty(KeyType.NAME, 'John');
Also, this should show an error:
MyClass.setProperty(KeyType.NAME, 5);
// 5 is not a string
In this example it doesn't work as the key
type is wrongly defined (key type is actually the value of the enum, so key type is 0
).
I am also open to suggestions about a different approach to having this functionality of only allowing a specific type for a specific parameter key.
You want to use function overloads to get the type checking working properly:
enum KeyType {
NAME,
AGE
}
class MyClass {
public static setProperty(key: KeyType.NAME, value: string): void;
public static setProperty(key: KeyType.AGE, value: number): void;
public static setProperty(key: KeyType, value: (string | number)): void {}
}
or simpler, just use strings:
class MyClass {
public static setProperty(key: 'name', value: string): void;
public static setProperty(key: 'age', value: number): void;
public static setProperty(key: string, value: (string | number)): void {}
}
MyClass.setProperty('name', 42); // Argument of type '"name"' is not assignable to parameter of type '"age"'.
MyClass.setProperty('age', 42); // Ok
MyClass.setProperty('name', 'foo'); // Ok
MyClass.setProperty('age', 'foo'); // Argument of type '"foo"' is not assignable to parameter of type 'number'.
And of course you don't have to list the literal strings in the overloads, you can group similar ones into a type definition:
type StringProperty = 'name' | 'address';
type NumberProperty = 'age' | 'salary';
class MyClass {
public static setProperty(key: StringProperty, value: string): void;
public static setProperty(key: NumberProperty, value: number): void;
public static setProperty(key: string, value: (string | number)): void {}
}
You could try this
MyClass.setProperty(key: KeyType, value: string |number) {
// check key type and throw error as appropriate
}
I'm using another approach, using an object.
For example: let's say that we are creating a function to send analytics data, so we have an event name and a payload about this event...
enum TEvents {
productView = 'web/product/view',
productPutInCart = 'web/product/put-in-cart'
}
type TLogEvent = ({ event, data }:
{
event: TEvents.productView,
payload: {
productId: number
}
} |
{
event: TEvents.productPutInCart,
payload: {
productId: number,
amount: number
}
}
) => void
const logEvent: TLogEvent = ({ event, data }) => {
...
javascript only contain object, so if you want to use enum, just define it like and object then call it like:
var enum1 = { SMALL:"asjdh", MEDIUM:2};
console.log(enum1.SMALL)
console.log(enum1.MEDIUM)
What about this approach - if your class has two properties like age and name, your setProperty function can get string or age and based on type assign to specific property, example:
class MyClass {
public age:number;
public name:string;
setProperty(value: string|number) {
if (typeof value === 'string') {
this.name = value;
} else if (typeof value === 'number') {
this.age = value;
}
}
}
let myClass = new MyClass();
myClass.setProperty("John");
console.log(myClass.name);
myClass.setProperty(60);
console.log(myClass.age);
Of course using this trick with value with two type (string or number) you can done it as you wanted:
setProperty(key: string, value: string|number) {
if (key === 'AGE') {
this.age = value;
} else if (key === 'NAME') {
this.name = value;
}
}
But in this case you need to write more code to protect this part.
©2020 All rights reserved.