-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Nominal typing and TypeScript > 2.7 #21625
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
Comments
Does the definite assignment assertion operator ( class Box<A> implements HK<"box", A> {
readonly _URI!: "box";
readonly _A!: A;
} |
Alternatively, declaration merging can resolve this, although @jack-williams's suggestion might be desirably more explicit. interface HK<F, A> {
readonly _URI: F
readonly _A: A
}
interface Box<A> extends HK<"box", A> { }
class Box<A> {} |
@ahejlsberg seems like a reasonable commitment? |
is there a chance we can see true hkt? i promise they are better than instantiating abstract classes |
I think yes, if it continues to work. The transition is a little painful as it's not compatible with TS 2.6, but I guess everybody will eventually upgrade. |
As it hadn't been mentioned yet, By the way, the TS compiler uses phantom type constructs for nominal typing internally itself as well, while a regression test is also present already. Maybe adding an extra test for this HK/Box scenario should do it? |
@alexandru the link you posted said the optimal representation in flow is a type level function; now that we have conditional types and |
The function types they're passing to |
any updates? |
2.7 also introduced declare const phantom: unique symbol;
type Dep<T> = string & { [phantom]?: T };
const foo: Dep<number> = 'foo';
function inject<T>(deps: [Dep<T>], callback: (a: T) => void) { }
inject([foo], (a) => {
console.log(a) // a is a number
}) |
on a side note, what is the meaning behind |
Bumping this up - still an issue that needs to be looked at. Nominal typing is required imo. |
You probably want to follow #202 for that |
Hello,
TypeScript is structurally typed, but sometimes we need nominal typing, for interfaces / types, not classes.
For example one instance where nominal typing is needed is in encoding higher kinded types, which are needed in functional programming libraries, like fp-ts and funfix. The encoding currently used goes like this:
These are known as "phantom types", aka types that don't have a runtime footprint, their sole purpose being to aid the compiler in doing static type checks.
Unfortunately TypeScript 2.7 is breaking this encoding due to its new restriction to have all
readonly
properties initialized in the constructor. So if we are to keep using such an encoding, then we'd have to do:But this is not acceptable, because it has runtime ramifications, both
_URI
and_A
being registered as properties onBox.prototype
and that's very uncool, for one because it implies extra memory usage, but also because this encoding is very TypeScript-specific, as for JavaScript engines / code this has no value and the optimal encoding for Flow is different.The current proposal is to use literal properties (with special chars that would make them unsuitable for usage as normal properties), which apparently TypeScript 2.7 doesn't touch:
My worry however is that this will be a temporary workaround.
I really do appreciate the tightening of the type system and the new strict settings that keep getting added, however as library authors we need an encoding that doesn't break between versions with the strictest settings active.
So, can we get an assurance that the above encoding won't break, or that if it does, it will get replaced by a feature that fixes this need (encoding of phantom types) for good?
And thanks for all your hard work 👏, in spite of TypeScript 2.7 breaking my code, the improvements look good and I understand more is on the way for 2.8.
Cheers,
The text was updated successfully, but these errors were encountered: