Instead of using literal values, generic types are fulfilled with type arguments (although there is room for some creative experimentation - but it's not necessary in this scenario).
You have the option to define a listType
as limited to string
, or even specify it as a string literal type. This can be implemented as shown below (appearing like a union type, yet possessing string values as its type components).
class Repository<T> {
private itemsRef: T[];
constructor(private db: AngularFireDatabase, listType: 'products' | 'customers') {
this.itemsRef = db.list(listType);
}
}
The drawback here lies in the fact that a user could potentially input an incompatible T
and listType
. To avoid this issue, consider developing a RepositioryFactory
.
Alternate Factory Approach
Below is a revised version featuring a factory method, designed to eliminate compatibility errors.
type ListType = 'products' | 'customers';
class Repository<T> {
private itemsRef: T[];
protected constructor(private db: AngularFireDatabase, listType: ListType) {
this.itemsRef = db.list(listType);
}
static getInstance(db: AngularFireDatabase, listType: 'products'): Repository<Product>;
static getInstance(db: AngularFireDatabase, listType: 'customers'): Repository<Customer>;
static getInstance(db: AngularFireDatabase, listType: ListType) {
switch (listType) {
case 'products':
return new Repository<Product>(db, listType);
case 'customers':
return new Repository<Customer>(db, listType);
default:
throw new Error(`No Respository<T> for ${listType}`);
}
}
}