使用来自两个相似接口的默认值进行对象分解

时间:2019-11-13 00:33:21

标签: typescript

我有两个接口,UserBankUserBankUser的界面大致如下:

interface BankUser extends User {
  banks: { [bank_id: string]: string};
  isSuper: boolean;
}

我有一个要传递UserBankUser的函数,并且我希望BankUser从中传递出来。如果是用户,则应为BankUser添加默认属性。

const cleanedUser = (user: User | BankUser): BankUser => {
  const {uid, displayName, email, phoneNumber, photoURL, banks = {}, isSuper = false} = user;
  return {uid, displayName, email, phoneNumber, photoURL, banks, isSuper} as BankUser;
}

我收到两个TS2339错误,指示类型User | BankUser上不存在bank和isSuper,例如:

  

TS2339:属性“银行”在类型User | BankUser上不存在

如果我在函数上方添加// @ts-ignore,它可以工作,并且我可以发送UserBankUser,但是我尽量避免这样做。有更好的方法来解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

如果没有在对象的类型中明确提及该对象,则TypeScript不喜欢查找该对象的属性。在这种情况下,User没有明确提及banksisSuper,因此会出现编译器错误。是的,BankUser确实具有这样的属性,但是user可能是User,因此是错误的。

如果要说服编译器查找该属性,则需要将user视为比User | BankUser更具体的内容。例如,您可以将其视为User & Partial<BankUser>。已知该类型具有User的所有属性,并且可选地来自BankUser的其他属性。这给你这个:

const cleanedUser = (user: User | BankUser): BankUser => {
    const {
        uid, displayName, email, phoneNumber, photoURL, banks = {}, isSuper = false
    } = user as User & Partial<BankUser>; // no error now
    return { uid, displayName, email, phoneNumber, photoURL, banks, isSuper };
}

另外,根据您的用例,我可能会像这样实现cleanedUser

const cleanedUser2 = (user: User | BankUser): BankUser => {
    return { banks: {}, isSuper: false, ...user };
}

这需要更少的类型操纵和更少的键入。如果您假设为cleanedUser传入的值完全是 userUser,并且它没有{额外的属性。


一旦您期望BankUser可能具有额外的属性,那么您可能需要更加小心usercleanedUser()的实现,因为类型为{{1} }可能具有类型cleanedUser2()的额外User属性。这是一个非常有效的isSuper,但是当您进行清洁时,您会发现奇怪的事情发生了:

number

所以要小心。


好的,希望能有所帮助;祝你好运!

Link to code