强制使用正确的财产

时间:2018-02-13 02:15:19

标签: typescript

让我们说我有一个代表用户登录并给出姓名的类型:

export interface User {
  login: string;
  name: string;
}

现在我想使用该用户的登录信息查询API:

const formatLogin (login: string) => login.toLowerCase().trim();
const getUser = (login: string) => ajax(`${API}/users/${formatLogin(login)}`);

这很有效。稍后在我的代码中我可能会使用:

getUser(this.user.name);

这是一个错误。它应该是this.user.login。它们都是字符串,因此TypeScript不会抱怨。

有没有办法强制使用TypeScript来使用属性?

我已尝试使用export type Username = string,但这不起作用,因为name仍然满足该类型,因为它只是string。我还尝试了export interface Username {} formatLogin,它不适用toLowerCase,这需要字符串方法triminterface Username extends String {}。 {{1}}有同样的问题。

2 个答案:

答案 0 :(得分:4)

一种方法是使用所谓的branded types,遵循TypeScript compiler itself来源中设置的示例:

export type LoginString = string & { __loginBrand: any};

export interface User {
  login: LoginString;
  name: string;
}


const formatLogin = (login: string) => login.toLowerCase().trim();
const getUser = (login: LoginString) => { };

let user: User;

formatLogin(user.login); // ok
getUser(user.name); // error

在初始化LoginString对象时,您必须手动将普通字符串转换为User类型,您不必为__loginBrand提供实际值 - 它'仅用于类型检查。

@estus建议的另一种方法是使用destructured对象作为API的一种命名参数。它没有经过类型检查,但任何不匹配都非常明显,只要所有名称始终在所有地方使用:

   export interface GetUser {
       login: string;
   }
   const getUser = ({login}: GetUser) => {}

   getUser(user); // ok
   getUser({login: user.name}); // huh?

答案 1 :(得分:1)

键入系统不可能区分这两个属性,因为它们是任意字符串。

这是测试覆盖率有助于消除人为错误的领域。

问题不是用类型解决,而是用合理的方法命名方法解决,不会留下任何错误。例如,这个错误

(x1,x[n+1])

更有可能吸引注意力。

根据具体情况,getUserByLogin(this.user.name); 不能接受字符串,而是接受对整个对象的引用,并从中获取所需的属性:

getUser