-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Allow intersected numbers to be used in arithmetics & element access #4372
Comments
I was thinking about this just for the sake of things like units of measure. As I mentioned in your PR, I think the only open questions are what to do with |
I would add that |
I agree that it doesn't give the best experience. To give some background why I'm using this, I'm working on a compiler that compiles TypeScript to LLVM. It currently only works with a very small subset, but I'm working on expanding that subset. Currently all variables should be a primitive (int32, int64, etc), a pointer or a struct. Brands are the only way to see the difference between an int32 and an int64 at the moment (as far as I know). I hope to put a preview on GitHub soon. Besides that, it is actually possible to create such object in JavaScript, by adding the property on the prototype: Number.prototype.extended = true;
3..extended; // true You could use this to check whether some methods are supported in the current environment: type ES6String = string & { includes(str: string): boolean; repeat(count: number): string};
function isES6String(str: string) str is ES6String {
return (<ES6String> str).includes !== undefined;
}
function repeat(str: string, count: number) {
if (isES6String(str)) {
return str.repeat(count);
} else {
// for (let i = 0...
}
} |
@jbondc Agree that it might look strange, but My example with strings is probably not the best one. My use case is branding numbers. In my project I need to distinguish different primitive numbers, like int32 and uint16. Set types would be a better solution to this, but they're not supported in TypeScript, it will probably require a lot work to implement that correctly. Branding with intersections is working, except for element access and arithmetics. I'd be open for other suggestions to distinguish different number types, other than intersections. Should I give more background info on my project? |
Short term, would this not work?
Gives a 'nominal' looking type system for numbers, enough to use the type names to emit types. Set types are a lot of work, but it would allow proper checking for things like:
Though haven't played around with intersection types. |
As far as I know the compiler api immediately expands a type alias to it's definition, so type int32 = number;
function returnsInt(): int32 {
return 0;
}
let i = returnsInt(); Checking the existence of a property is simple using the compiler api, while this approach would (if I'm not mistaken) require a lot more work. Type checking is indeed important, but at the moment I can live without it. |
Hmm right, some hack would be needed here: Replace which would 'create' new intrinsic primitive types:
Think you'd need to change === numberType in several places to (type.flags & TypeFlags.Number). Best quick hack I can think of 😄 |
@ivogabe Here's the hack: |
@jbondc Thanks! I think I can get it working with that. Downside of that is that I need to maintain a fork, what I prefer not to do. Would the team be interested in merging such feature, or a different way to create subtypes of primitives? |
I do not think so. this is a very specialized |
Can you give some more details on this? Would this mean that these are hard coded or user defined? Are you referring to set types (with ranges)? I can try to write a proposal and PR if you'd like. |
I've an idea that would fit well in TypeScript: it doesn't require type information for emit (thus works with |
@ivogabe we do not have plans for doing this in the near term. but would be interested to see your proposal. |
I've written the proposal, see #4639 |
|
with #4639, i do not think this proposal is needed any longer. |
Agree about that. I figured out I can use this today: namespace std {
enum Int8 {}
enum Uint8 {}
// etc
export type int8 = number | Int8;
export type uint8 = number | Uint8;
} Using this I can distinguish different number types using the compiler api. Built in support for integers would be better though. |
I was experimenting with intersection types and primitives, and I discovered that when you create an intersection type with a number, you can't use it in arithmetics and element access:
Though you can't create properties on numbers, this can be useful to add brands to numbers, like this:
Currently intersections are only allowed on these locations if all parts of the intersection are number or string, but that rule should only apply to union types. Suggestion: for intersection types (at least) one type should be number (or string) if it's used in arithmetics or element access.
I've implemented a fix in #4373.
The text was updated successfully, but these errors were encountered: