-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Phantom types #1056
Comments
I think the missing feature is opaque types. Currently, type aliases are transparent. If you have export type URIString= string; Then anyone who imports Hack does this with the // URIString.js
type URIString = string;
export function encode(s: string): URIString {
return encodeURI(s);
}
export function decode(s: URIString): string {
return decodeURI(s);
}
export opaque type { URIString };
// Other module
import { encode, decode } from './URIString';
var encoded_string = encode('Hi there'); // No error
var decoded_string = decode(encoded_string); // No error
decide("Other string"); // Error: string ~> URIString
encode(encoded_string); // Error: URIString ~> string If we had that, then you could create your phantom types as opaque. Then they would be checked nominally and the errors would reference them therefore by name. Though now that I've written this, there's another feature which I'm not sure how it would fit in. With opaque types, it's nice sometimes to be able to specify a subtyping behavior. Like we might like to say that // URIString.js
newtype URIString as string = string;
export function encode(s: string): URIString {
return encodeURI(s);
}
export function decode(s: URIString): string {
return decodeURI(s);
}
export type { URIString };
// Other module
import { encode, decode } from './URIString';
var encoded_string = encode('Hi there'); // No error
var decoded_string = decode(encoded_string); // No error
decide("Other string"); // Error: string ~> URIString
encode(encoded_string); // No error, since URIString is a subtype of string |
See some earlier discussion in #465. I recently hacked together an interface file for testcheck that uses classes to simulate an opaque type. |
I believe I've stumbled upon a nicer way to do this while working around a limitation with the current support for // @flow
// Properties.js
export class Margin {}
export class Padding {} // @flow
// index.js
// export * from "./Properties";
import * as Properties from "./Properties";
export type Margin = Properties.Margin;
export type Padding = Properties.Padding; Using this approach |
+1 |
I really want this feature to distinguish |
+1 this is important to differentiate Int from Float. This avoids human errors where we forget to round float to int value and cause errors down the road. |
Also, it's something that Hack for PHP already supports. I hope this comes
around for JS as well soon...
…On Mon, May 22, 2017, 20:11 simprince ***@***.***> wrote:
+1 this is important to differentiate Int from Float. This avoids human
errors where we forget to round float to int value and cause errors down
the road.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#1056 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ACmsItVJ1pzsYfa_eUzxNBjo8oJ3-gsEks5r8c-7gaJpZM4GePRJ>
.
|
Perhaps a syntax like type URIString = $Opaque<string>; would be useful before adding concrete keywords. This falls in line with other private types such as |
Closing since opaque types went out in 0.51 |
I was talking to @jeffmo on IRC about this and was asked to create an issue.
I have a project where I'm using some types purely as type constraints, or phantom types. This is currently available at https://github.com/paulyoung/tss.
In order to make sure these types can't be constructed I must do the following:
This way, even if someone does
import { Foo } from Bar
instead ofimport type { Foo } from Baz
,new Foo()
causes the errorConstructor cannot be called on type
Foo``.However, this has the undesired result of the error for an incorrect type to read
This type is incompatible with _Foo
, rather than when simply doingexport class Foo {}
which yieldsThis type is incompatible with Foo
.I'm also unsure how to create a declaration file that achieves the same behavior (or even if this is necessary, but it seemed to be the only way to use one flow-annotated project inside another).
I'd prefer some way of exporting an anonymous type, perhaps something like this:
Of course, this would require that
Foo
andBar
are considered to be different types.If there are any other ways to achieve this currently, I'd love to know how.
Thanks!
The text was updated successfully, but these errors were encountered: