别名类型可以减少样板并提高可读性,但是它比别名类型本身更安全。考虑以下:
type alias Email = String type alias Name = String someEmail = "holmes@private.com" someName = "Benedict" sendEmail : Email -> Cmd msg sendEmail email = ...
使用上面的代码,我们可以编写sendEmail someName,即使它实际上不应该编译,也可以编译,因为尽管名称和电子邮件都是Strings,但它们是完全不同的。
通过创建新的类型,我们可以在类型级别上真正区分String另一个。这是一个改写为而不是的示例:StringEmailtypetype alias
module Email exposing (Email, create, send) type Email = EmailAddress String isValid : String -> Bool isValid email = -- ...validation logic create : String -> Maybe Email create email = if isValid email then Just (EmailAddress email) else Nothing send : Email -> Cmd msg send (EmailAddress email) = ...
我们的isValid函数会执行某些操作来确定字符串是否为有效的电子邮件地址。该create函数检查给定String的电子邮件是否有效,并返回Maybe-wrappedEmail以确保我们仅返回经过验证的地址。如果我们的模块声明未公开构造函数,则Email可以通过直接编写来避开验证检查,如此处所示EmailAddress "somestring"EmailAddress
module Email exposing (Email, create, send)
那么其他模块将无法访问EmailAddress构造函数,尽管它们仍可以Email在注释中使用该类型。在此模块之外构建新的唯一方法Email是使用create它提供的功能,并且该功能可确保首先仅返回有效的电子邮件地址。因此,此API会通过其类型安全性自动将用户引导至正确的路径:send仅适用于由构造的值create,该值执行验证,并由于返回a来强制处理无效电子邮件Maybe Email。
如果要导出Email构造函数,可以编写
module Email exposing (Email(EmailAddress), create, send)
现在,任何Email导入的文件也可以导入其构造函数。在这种情况下,这样做会使用户避开验证和send无效的电子邮件,但是您并不总是构建这样的API,因此导出构造函数可能会很有用。对于具有多个构造函数的类型,您可能还只希望导出其中一些构造函数。