Reputation: 105
So, I want to create TS class with optional param and fallback it's keys:
class NiceClass {
private format: string;
private total: number;
private current: number;
private width: number;
private head: string;
private complete: string;
private incomplete: string;
private tail: string;
constructor (format: string, total: number, options?: any) {
this.format = format;
this.total = total;
if (options) {
this.current = (typeof options.current == 'number') ? options.current : 0
this.width = (typeof options.width == 'number') ? options.width : 20
this.head = (typeof options.head == 'string') ? options.head : '^'
this.complete = (typeof options.complete == 'string') ? options.complete : '+'
this.incomplete = (typeof options.incomplete == 'string') ? options.incomplete : '-'
this.tail = (typeof options.tail == 'string') ? options.tail : '$'
} else {
this.current = 0
this.width = 20
this.head = '^'
this.complete = '+'
this.incomplete = '-'
this.tail = '$'
}
}
public async add(increase: number = 1): Promise<void> {
// some functionallity
}
}
export default NiceClass;
So it can be used like so:
const nice = new NiceClass('nice format', 50); // without any option
// or
const nice = new NiceClass('nice format', 50, { // with some option(s)
current: 25,
head: '/'
});
// or
const nice = new NiceClass('nice format', 50, { // with all options
current: 25,
width: 5,
head: '/',
complete: 'x',
incomplete: ' ',
tail: '\'
});
The above script works fine, but I think it could be improved and look much cleaner, since:
(increase: number = 1)
instead of this.increase = (typeof increase == 'number') ? increase : 0
(options?: any)
The problem is I can't figure it out how to do this
P.S: I'm totally new to TS, so sorry if it's basic stuff.
Upvotes: 0
Views: 1494
Reputation: 11
One way you can achieve what you're looking for in a clean way is using object spread with a defaultOptions object. Take a look at this code.
class MyClass {
private format: string;
private total: number;
private options: {
current: number;
width: number;
head: string;
complete: string;
incomplete: string;
tail: string;
}
constructor(format: string, total: number, options?:
{
current?: number,
width?: number,
head?: string,
complete?: string,
incomplete?: string,
tail?: string
}) {
const defaultOptions = {
current: 0,
width: 20,
head: '^',
complete: '+',
incomplete: '-',
tail: '$'
}
this.format = format;
this.total = total;
this.options = { ...defaultOptions, ...options };
}
}
console.log(new MyClass('myformat', 100, { width: 50 }));
Upvotes: 1
Reputation: 2240
You could use JavaScript default arguments for your use case:
class NiceClass {
private format: string;
private total: number;
private current: number;
private width: number;
private head: string;
private complete: string;
private incomplete: string;
private tail: string;
constructor (format: string, total: number, options: {current: number; width: number; head: string; complete: string; incomplete: string; tail: string} = {
current: 0,
width: 20,
head: '^',
complete: '+',
incomplete: '-',
tail: '$'
}) {
this.format = format;
this.total = total;
this.current = options.current;
this.width = options.width;
this.head = options.head;
this.complete = options.complete;
this.incomplete = options.incomplete;
this.tail = options.tail;
}
public async add(increase: number = 1): Promise<void> {
// some functionallity
}
}
Notice, I've also typed the shape of your options argument to ensure that if you do pass options to your constructor, that the values respect the types for each property (e.g. the current
property must be a number).
Upvotes: 0
Reputation: 1074295
There's no shorthand / shortcut if you want to specifically test for the number type (or string type, etc., as opposed to undefined
for a missing property on the options object), but you don't need to do that in TypeScript anyway since it provides type safety through the static type system.
You define an interface for your options, like this:
interface ExampleOptions {
current?: number ,
width?: number ,
head?: string ,
complete?: string ,
incomplete?: string ,
tail?: string
}
Then use destructuring assignment with default values in the constructor, like this:
constructor (
format: string,
total: number,
// Destructuring the options object
{
current = 0, // Individual defaults
width = 20,
head = "^",
complete = "+",
incomplete = "-",
tail = "$"
}: ExampleOptions = {} // Defaulting the object entirely
// ^^^^^^^^^^^^^^−−−−−−−− Type for the options object
) {
this.format = format;
this.total = total;
this.current = current;
this.width = width;
this.head = head;
this.complete = complete;
this.incomplete = incomplete;
this.tail = tail;
}
The defaults get used if the options object doesn't have the relevant property (or if it has the value undefined
). If you leave off the options object entirely, the = {}
default kicks in, and then the destructuring defaults apply because that object doesn't have any of the properties.
Upvotes: 1