【问题标题】:Object destructuring with default values from two similar interfaces使用来自两个相似接口的默认值的对象解构
【发布时间】:2019-11-14 00:25:35
【问题描述】:

我有两个接口,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 错误,表明银行和 isSuper 在类型 User | BankUser 上不存在,例如:

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

如果我在函数上方添加// @ts-ignore,它会起作用,我可以发送UserBankUser,但我尽量避免这种情况。有没有更好的方法来处理这个问题?

【问题讨论】:

  • 您的错误是指IUser的类型,但此代码中未定义此类型。
  • @kaya3 哎呀。谢谢你抓住那个。实际使用的命名约定有点复杂,所以我在示例中对其进行了更改以使其更加清晰。现在已经解决了。

标签: typescript


【解决方案1】:

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 };
}

这需要更少的类型操作和更少的输入。如果您假设为user 传递的值完全UserBankUser 并且没有额外的属性,则它具有与cleanedUser 相同的行为。


一旦您期望user 可能有额外的属性,那么您可能需要更加小心cleanedUser()cleanedUser2() 的实现,因为User 类型的值可能有,比如说,额外的isSuper 类型为 number 的属性。这是一个完全有效的User,但你会在清洁时看到奇怪的事情发生:

interface Hmm extends User {
    isSuper: number;
}
const hmm: Hmm = {
    uid: "", email: "", displayName: "", phoneNumber: "", photoURL: "", isSuper: 100
};
const beCareful = cleanedUser(hmm);
console.log(beCareful.isSuper) // boolean at compile time, number at runtime !!!

所以要小心。


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

Link to code

【讨论】:

  • 谢谢。我在 cleanUser 函数中如此冗长的部分原因是我像 lodash.pick() 一样使用它来删除任何不需要的属性。我曾尝试过 Partial,但这也不起作用。
  • 有趣...使用 (user: Partial) 不会显示任何错误。我想这是有道理的......我认为这就是我现在要采取的路线。感谢您深入研究!
猜你喜欢
  • 1970-01-01
  • 2020-04-09
  • 1970-01-01
  • 2022-01-23
  • 2019-09-30
  • 1970-01-01
  • 1970-01-01
  • 2020-04-17
  • 1970-01-01
相关资源
最近更新 更多