Reputation: 2344
See this playground: Playground
export interface IProduct {
productId: number;
}
export interface ICompany {
companyId: number;
}
function click(type: 'product', entity: IProduct): string;
function click(type: 'company', entity: ICompany): string;
function click<T>(type: 'product' | 'company', entity: T) {
if (type === 'product') {
return 'product ' + entity.productId;
} else if (type === 'company') {
return 'company ' + entity.companyId;
}
throw new Error('wrong input');
}
click('product', { productId: 123 });
How do I make typescript understand, that if the first if evaluates true, then the second argument is an IProduct
?
Upvotes: 0
Views: 75
Reputation: 2663
function click(type: 'product', entity: IProduct): string;
function click(type: 'company', entity: ICompany): string;
function click<T extends IProduct | ICompany>(type: 'product' | 'company', entity: T) {
if (type === 'product' && assertType(type, entity)) {
return 'product ' + entity.productId;
} else if (type === 'company' && assertType(type, entity)) {
return 'company ' + entity.companyId;
}
throw new Error('wrong input');
}
function assertType(type: 'product', entity: IProduct | ICompany): entity is IProduct;
function assertType(type: 'company', entity: IProduct | ICompany): entity is ICompany;
function assertType(type: 'product' | 'company', entity: IProduct | ICompany): entity is IProduct | ICompany {
return entity && type === "product" || type === "company";
}
function click(entity: IProduct | ICompany) {
// here: (parameter) entity: IProduct | ICompany
if ("productId" in entity) {
// here: (parameter) entity: IProduct
return `product ${entity.productId}`;
} else if ("companyId" in entity) {
// here: (parameter) entity: ICompany
return `company ${entity.companyId}`;
}
throw new Error('wrong input');
}
Upvotes: 0
Reputation: 37918
You could type arguments as union of tuples, but it is ugly because destructuring can't be used (typescript will loose type relation):
function click(type: 'product', entity: IProduct): string;
function click(type: 'company', entity: ICompany): string;
function click(...args: ['product', IProduct] | ['company', ICompany]) {
if (args[0] === 'product') {
return 'product ' + args[1].productId;
} else if (args[0] === 'company') {
return 'company ' + args[1].companyId;
}
throw new Error('wrong input');
}
Upvotes: 2