Typescript:根据另一个参数键入一个参数

Typescript:根据另一个参数键入一个参数,typescript,Typescript,看看这个操场: 导出接口IPProduct{ productId:编号; } 出口接口公司{ 公司ID:编号; } 函数单击(类型:“产品”,实体:IPProduct):字符串; 函数单击(类型:“公司”,实体:ICompany):字符串; 功能点击(类型:“产品”|“公司”,实体:T){ 如果(类型==‘产品’){ 返回'product'+entity.productId; }else if(类型==‘公司’){ 返回“company”+entity.companyId; } 抛出新错误(“输

看看这个操场:

导出接口IPProduct{
productId:编号;
}
出口接口公司{
公司ID:编号;
}
函数单击(类型:“产品”,实体:IPProduct):字符串;
函数单击(类型:“公司”,实体:ICompany):字符串;
功能点击(类型:“产品”|“公司”,实体:T){
如果(类型==‘产品’){
返回'product'+entity.productId;
}else if(类型==‘公司’){
返回“company”+entity.companyId;
}
抛出新错误(“输入错误”);
}
单击('product',{productId:123});

我如何让typescript理解,如果第一个if值为true,那么第二个参数是
IPProduct

您可以将参数输入为元组的并集,但这很难看,因为无法使用解构(typescript将失去类型关系):


您可以将参数输入为元组的并集,但这很难看,因为无法使用解构(typescript将失去类型关系):

有效的解决方案(但不是好的):
函数单击(类型:'product',实体:ipproduct):字符串;
函数单击(类型:“公司”,实体:ICompany):字符串;
功能点击(类型:“产品”|“公司”,实体:T){
if(类型==‘产品’&&assertType(类型,实体)){
返回'product'+entity.productId;
}else if(类型===‘公司’&&assertType(类型,实体)){
返回“company”+entity.companyId;
}
抛出新错误(“输入错误”);
}
功能资产类型(类型:“产品”,实体:IPProduct | ICompany):实体为IPProduct;
功能资产类型(类型:“公司”,实体:IPProduct | ICompany):实体为ICompany;
功能资产类型(类型:“产品”|“公司”,实体:IPProduct | ICompany):实体是IPProduct | ICompany{
返回实体和类型==“产品”| |类型==“公司”;
}

更好的解决方案(在我看来):
功能点击(实体:IPProduct | ICompany){
//此处:(参数)实体:IPProduct | ICompany
if(实体中的“productId”){
//此处:(参数)实体:IPProduct
返回`product${entity.productId}`;
}else if(实体中的“公司ID”){
//此处:(参数)实体:ICompany
返回'company${entity.companyId}';
}
抛出新错误(“输入错误”);
}

有效的解决方案(但不是好的):
函数单击(类型:'product',实体:ipproduct):字符串;
函数单击(类型:“公司”,实体:ICompany):字符串;
功能点击(类型:“产品”|“公司”,实体:T){
if(类型==‘产品’&&assertType(类型,实体)){
返回'product'+entity.productId;
}else if(类型===‘公司’&&assertType(类型,实体)){
返回“company”+entity.companyId;
}
抛出新错误(“输入错误”);
}
功能资产类型(类型:“产品”,实体:IPProduct | ICompany):实体为IPProduct;
功能资产类型(类型:“公司”,实体:IPProduct | ICompany):实体为ICompany;
功能资产类型(类型:“产品”|“公司”,实体:IPProduct | ICompany):实体是IPProduct | ICompany{
返回实体和类型==“产品”| |类型==“公司”;
}

更好的解决方案(在我看来):
功能点击(实体:IPProduct | ICompany){
//此处:(参数)实体:IPProduct | ICompany
if(实体中的“productId”){
//此处:(参数)实体:IPProduct
返回`product${entity.productId}`;
}else if(实体中的“公司ID”){
//此处:(参数)实体:ICompany
返回'company${entity.companyId}';
}
抛出新错误(“输入错误”);
}

如何使用
返回“产品”+实体[“产品ID”]正如您在这里所知道的,在这里查找并获取什么类型的参数?使用
返回'product'+实体[“productId”]如何
正如您在这里所知道的,在这里查找并获取什么类型参数?如果我们知道在需要匹配特定类型时要查看的确切属性,那么为什么不将其简化为
返回'product'+实体[“productId”]
?@Sohan,因为这不适用于
noImplicitAny
entity.productId
entity[“productId”]
)相同。如果我们知道在需要匹配特定类型时要查看的确切属性,那么为什么不将其简化为
return'product'+entity[“productId”]
?@Sohan,因为这不适用于
noImplicitAny
entity.productId
entity[“productId”]
相同).我不太喜欢后者,因为如果将来出于任何原因将属性
productId
添加到公司实体中,我们将产生意想不到的副作用。不过,感谢前面的建议!@BartvandenBurg嗯,如果你仔细想想,TypeScript中的接口只是语义。因此,实际上由于
productId
确实实现了
ipproduct
。JavaScript是鸭型的。如果你真的想确保对象本身捕获类型,你可以使用具体的类和
instanceof
关键字,或者添加一个定义对象类型的
type
属性。我不太喜欢后者,因为如果将来出于任何原因将属性
productId
添加到公司实体中,我们将产生意想不到的副作用。不过感谢前面的建议!@Bartenburg好吧,仔细想想,TypeScript中的接口只是语义而已。因此,实际具有
productId
的对象确实实现了
IProduct
。JavaScript是duck类型的。如果确实想确保对象本身捕获类型,可以使用具体类和
instanceof
关键字,或者添加一个定义对象类型的
type
属性,请参见
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 });
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');
}