【问题标题】:Angular 7 map firebase UserInfo to custom User modelAngular 7将firebase UserInfo映射到自定义用户模型
【发布时间】:2019-02-10 15:28:13
【问题描述】:

我是 Angular 7 的新手,我试图从 firebase 获取当前经过身份验证的用户并映射到我自己的 User 模型(User 中没有构造函数)。

在 Firebase API 中:

interface UserInfo {
  displayName: string | null;
  email: string | null;
  phoneNumber: string | null;
  photoURL: string | null;
  providerId: string;
  uid: string;
}

在我自己的模型中:

export class User{
  name: string;
  email: string;
  contactNo: string;
} 

我的UserService

@Injectable()
export class UserService {

  constructor(
    private fireAuth: AngularFireAuth, 
  ) {}

  getAuthUser(): Observable<User> {

    // this part is not working, how to map to User without changing User constructor?
    return this.fireAuth.authState.map(authData => new User({name: authData.displayName}));

  }

}

【问题讨论】:

    标签: angular firebase rxjs firebase-authentication angular7


    【解决方案1】:

    根据Angular Style Guide:

    考虑为数据模型使用接口。

    话虽如此,如果您愿意遵循该样式指南,则可以这样做:

    使用可选字段创建User interface:

    export interface User{
      name?: string;
      email?: string;
      contactNo?: string;
    }
    

    在您的服务中,您可以简单地执行以下操作:

    @Injectable()
    export class UserService {
    
      constructor(
        private fireAuth: AngularFireAuth,
      ) {}
    
      getAuthUser(): Observable<User> {
        return this.fireAuth.authState.map(authData => ({
          name: authData.displayName
        }));
      }
    
    }
    

    【讨论】:

    • 我尝试按照map的上述建议(不将数据模型更改为接口),它说Type 'Observable&lt;{ name: string; }&gt;' is not assignable to type 'Observable&lt;User&gt;'.。
    • 你做了一个界面,把Userinterface中的所有字段都设为可选吗?
    • 哦,我将User 中的所有字段都标记为可选并且它有效,为什么我们必须将所有字段标记为可选?
    • 您不必这样做。如果你愿意,这只是让你用更少的字段定义类型的一种方式。
    • @hades,这是因为 User 类型不一定总是包含所有字段。在这种情况下,名称字段可用。在某些情况下,它将不可用。例如,当您实施电话登录时。因此,最好将它们全部保留为可选。
    【解决方案2】:

    问题编辑后

    我仍然推荐“在问题被编辑之前”的答案,但要回答问题:

    new User({name: authData.displayName}) 不能在不调整构造函数的情况下工作。一个类有一个默认构造函数,在你的例子中是User(),它不接受任何参数。如果您必须或想要使用类而不是接口(如下所述),那么您应该可以使用一些解决方法。

    粗略的例子:

    // object "as"
    authData => <User>{name: authData.displayName, ... other props}
    
    // object "as" 2
    authData => {name: authData.displayName, ... other props} as User
    
    // new user, return after changing props
    authData => {
        const user = new User();
        user.name = authData.displayName;
        // ...the rest
        return user;
    }
    
    // "builder" method (basically a constructor)
    function buildUser(name: string, ...other props) {
        const user = new User();
        user.name = authData.displayName;
        // ...the rest
        return user;
    }
    

    问题被编辑之前 如果你不想使用构造函数并且类只是一个没有额外方法的模型,我建议使用接口。

    // interface
    export interface User {
      name: string;
      email: string;
      contactNo: string;
    }
    
    // inside map
    authData => {name: authData.displayName, ...<other props>}
    
    // inside map with type checking 1
    authData => <User>{name: authData.displayName, ...<other props>}
    

    This answer 有更多详细信息。

    【讨论】:

    • 谢谢,你的方法也可以,但是在阅读了你的链接之后,我仍然对使用interface 而不是class 进行数据模型的好处感到困惑,介意简单解释一下吗?
    • 我只想说,如果它不会真正为您的特定案例增加任何价值,那么您实际上并不需要一个类。如果您认为您只需要一种通过模型输入用户数据的方法,仅此而已,那么创建一个类将没有多大意义。此外,由于未编译接口,因此它们不会在您的主包中可用。甚至 Angular 也建议将 interfaces 用于数据模型,正如我在回答中所链接的那样。
    • 有多种好处。基本上一个接口只是开发/编译时的糖,它给你很多好处,比如类型检查,但不包含在最终的 js 中。同样,它允许您更轻松地设置对象 &lt;ABC&gt;{a: 'a', b: 'b', c: 'c'} 的属性,并允许它适用于任何接受需要这两个字段的对象的对象。 basarat.gitbooks.io/typescript/docs/types/interfaces.html 例如:fun1(param: {a: string}) fun2(param: {a: string, b: string} fun3({a, b, c}: ABC).
    • 下面是一个简单的例子(es5):typescriptlang.org/play/…
    猜你喜欢
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 2020-10-01
    • 2018-03-15
    • 2012-02-08
    • 2021-11-20
    相关资源
    最近更新 更多