首页 > 解决方案 > TypeScript:接口多态性问题

问题描述

我有一个基本帐户界面:

interface Account {
  id: number;
  email: string;
  password: string;
  type: AccountType;
}

其中AccountType

enum AccountType {
  Foo = 'foo',
  Bar = 'bar'
}

以及扩展Account接口的两个帐户子类型(FooAccountBarAccount) :

interface FooAccount extends Account {
  foo: Foo;
}
interface BarAccount extends Account {
  bar: Bar;
}

Account是包含基本帐户信息的聚合体,并且根据类型,拥有FooBar对象。

对这些对象的操作只能由其所有者(帐户)执行。

我已经定义了一个AccountRepository

export interface AccountRepository {
  findById(accountId: number): Account;
}

其中findById(accountId: number)返回一个Account,但该帐户可以是任何FooAccountBarAccount

我想在对 a或findById执行任何操作之前使用此功能。例如,假设我想更新一个帐户的:FooBarFoo

这里的问题是,最后一点失败了: asfindById(accountId: number): Account返回一个Accountfoo: Foo并且在其接口中没有定义属性。

我也尝试了以下方法,但也无法做到:

const fooAccount: FooAccount = findById(accountId);

因为该函数返回一个Account

我试图弄清楚如何实现这一目标,我错过了什么?有什么我可能做错了吗?

标签: javascripttypescriptoop

解决方案


最好的解决方案可能是使用有区别的联合。

export class Bar { public idBar: number; }
class Foo { public idFoo: number; }
interface AccountCommon {
  id: number;
  email: string;
  password: string;
}

enum AccountType {
  Foo = 'foo',
  Bar = 'bar'
}

interface FooAccount extends AccountCommon {
  type: AccountType.Foo; // type can only be Foo
  foo: Foo;
}
interface BarAccount extends AccountCommon {
  type: AccountType.Bar; // type can only be Bar
  bar: Bar;
}
// The discriminated union
type Account = BarAccount | FooAccount //type is common so type can be either Foo or Bar

export interface AccountRepository {
  findById(accountId: number): Account;
}

let r: AccountRepository;

let a = r.findById(0);
if (a.type === AccountType.Bar) { // type guard
  a.bar.idBar // a is now BarAccount
} else {
  a.foo.idFoo // a is now FooAccount
}

推荐阅读