Title: Subtraction types · Issue #4183 · microsoft/TypeScript · GitHub
Open Graph Title: Subtraction types · Issue #4183 · microsoft/TypeScript
X Title: Subtraction types · Issue #4183 · microsoft/TypeScript
Description: Another type-safety measure. Sometimes it's desired to limit what developers can do with a value. Not allowing them to get to certain properties of it looks sufficient. Example: We render HTML elements to PDF on the client side. In order...
Open Graph Description: Another type-safety measure. Sometimes it's desired to limit what developers can do with a value. Not allowing them to get to certain properties of it looks sufficient. Example: We render HTML elem...
X Description: Another type-safety measure. Sometimes it's desired to limit what developers can do with a value. Not allowing them to get to certain properties of it looks sufficient. Example: We render HTML ...
Opengraph URL: https://github.com/microsoft/TypeScript/issues/4183
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Subtraction types","articleBody":"Another type-safety measure. Sometimes it's desired to limit what developers can do with a value. Not allowing them to get to certain properties of it looks sufficient. \r\n\r\nExample: We render HTML elements to PDF on the client side. In order to do so we need to run `element.getBoundingClientRect` to get a bounding box in effect. It is an expensive operation that we wish could only be done once and then the result of it would be passed around along with the element to be rendered. Unfortunately nothing stops developers from ignoring that result and running the same method again and again as long as they can get to `element.getBoundingClientRect`. Now I wish I could strip that method so no-one can see it once the box is calculated. Subtaction types would solve the problem.\r\n\r\n``` typescript\r\ntype HTMLDivSpecifics = HTMLDivElement - Element;\r\n```\r\n\r\n# Proposal\r\n\r\nadd a type operator that produces a new type out of 2 given types according to the rules that follow:\r\n\r\n```typescript\r\ntype C = A - B;\r\n```\r\nThis feature would require a new **negated** type like `number ~ string` which is a `number` that cannot take `number \u0026 string`.\r\n\r\nAs far as the precedence of new type operator, it should go:\r\n\r\n1. intersection `\u0026`\r\n2. union `|`\r\n3. subtraction `-`\r\n\r\nso that `number \u0026 boolean | string - string`, means `((number \u0026 boolean) | string) - string`\r\n\r\n### Generics\r\n- should produce a yet to be resolved type, should be stored as an expression which will produce either a type or an error when all type parameters are known\r\n\r\n```typescript\r\ntype Minus\u003cA, B\u003e = A - B; // yet to be calculated\r\n```\r\n\r\n### Primitives\r\n- if the left type (minued) isn't a sub-type of the right type (subtrahend) the `-` operation should result to an type error\r\n- `never` and `any` should be specially handled\r\n\r\n```typescript\r\ntype C = number - number; // {}\r\ntype C = number - {}; // number\r\ntype C = {} - number; // error\r\ntype C = number - string; // error\r\ntype C = number - 0; // number ~ 0\r\n\r\ntype C = number | string - boolean; // error\r\ntype C = number - void | null | undefined; // error\r\n\r\ntype C = number - any; // {}\r\ntype C = any - any; // any\r\ntype C = any - number; // any ~ number\r\ntype C = any - never; // error;\r\ntype C = never - any; // error;\r\ntype C = number - never; // error\r\ntype C = never - number; // error\r\ntype C = never - never; // error\r\n\r\ntype C = number | string - string; // number\r\ntype C = number - number | string; // {}\r\ntype C = number | string - {}; // number | string\r\n\r\ntype C = number \u0026 string - boolean; // error\r\ntype C = number \u0026 string - string; // number ~ string\r\n\r\n```\r\n\r\n### Products\r\n- only matching properties should be considered, non-matching properties of the left type should stay intact, non-matching properties of the right type should be disregarded\r\n- if the names of 2 properties match their types are subject for `-` operation that produces the type of the resulting property of the same name \r\n- if applying `-` on 2 properties of the same name gives `{}`, the property gets dropped from the resulting type\r\n\r\n```typescript\r\ntype C = {} - { x: number }; // {}\r\ntype C = { x: number } - {}; // { x: number }\r\ntype C = { x: {} } - { x: number }; // error\r\ntype C = { x: number } - { x: {} }; // { x: number }\r\ntype C = { x: number } - { y: number }; // { x: number }\r\ntype C = { x: number } - { x: number }; // {}\r\ntype C = { x: number | string } - { x: string }; // { x: number }\r\ntype C = { x: number \u0026 string } - { x: string }; // { x: number ~ string }\r\ntype C = { x: number } - { x: string }; // error\r\n```\r\n\r\n### Functions (2 certain signatures)\r\n- both functions must have the same number of parameters, otherwise it's an error\r\n- types of corresponding parameters are subject to the `-` operator\r\n- types of results must 100% match and should be kept intact, otherwise it's an error\r\n- if `-` on 2 parameters gives `{}` the resulting parameter is `{}`\r\n- if all resulting parameters are `{}` the resulting type is `{}`\r\n\r\n```typescript\r\ntype C = ((x: number) =\u003e string) - ((x: number) =\u003e string); // {}\r\ntype C = ((x: number) =\u003e number) - ((x: number) =\u003e number); // (x: {}) =\u003e number\r\ntype C = ((x: number | string) =\u003e string) - ((x: string) =\u003e string); // (x: number) =\u003e string\r\ntype C = ((x: number) =\u003e string) - ((x: string) =\u003e string); // error\r\ntype C = ((x: number | string) =\u003e string) - (() =\u003e string); // error\r\ntype C = (() =\u003e string) - ((x: number) =\u003e string); // error\r\n```\r\n\r\n### Overloads\r\n- to be continued...\r\n","author":{"url":"https://github.com/zpdDG4gta8XKpMCd","@type":"Person","name":"zpdDG4gta8XKpMCd"},"datePublished":"2015-08-06T08:51:24.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":80},"url":"https://github.com/4183/TypeScript/issues/4183"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:d2d7dd16-3dcd-eef3-597d-958ea71f65ea |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8632:189C82:31AD09D:32FB3E9:6A632214 |
| html-safe-nonce | 5b48db4980db76df0f6d30498c72956bc9593952dd360968d984e57a1d2d3bea |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4NjMyOjE4OUM4MjozMUFEMDlEOjMyRkIzRTk6NkE2MzIyMTQiLCJ2aXNpdG9yX2lkIjoiOTAyMjc2ODM2Njk0NDk4NTYyMSIsInJlZ2lvbl9lZGdlIjoic2VhIiwicmVnaW9uX3JlbmRlciI6InNlYSJ9 |
| visitor-hmac | 71fe2dfbd001209bbde3b12cb185839045c134bb642c2929d06c918ece5df4c8 |
| hovercard-subject-tag | issue:99388722 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/microsoft/TypeScript/4183/issue_layout |
| twitter:image | https://opengraph.githubassets.com/624891289e8882a8048cdec77c49e53f0eaab8c226522e3c886966fc516e50ae/microsoft/TypeScript/issues/4183 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/624891289e8882a8048cdec77c49e53f0eaab8c226522e3c886966fc516e50ae/microsoft/TypeScript/issues/4183 |
| og:image:alt | Another type-safety measure. Sometimes it's desired to limit what developers can do with a value. Not allowing them to get to certain properties of it looks sufficient. Example: We render HTML elem... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | zpdDG4gta8XKpMCd |
| hostname | github.com |
| expected-hostname | github.com |
| None | 1a6c056e02f174fffc096c521ec0ff6fb83e40a2ec8cb8875466ec1524872dd6 |
| turbo-cache-control | no-preview |
| go-import | github.com/microsoft/TypeScript git https://github.com/microsoft/TypeScript.git |
| octolytics-dimension-user_id | 6154722 |
| octolytics-dimension-user_login | microsoft |
| octolytics-dimension-repository_id | 20929025 |
| octolytics-dimension-repository_nwo | microsoft/TypeScript |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 20929025 |
| octolytics-dimension-repository_network_root_nwo | microsoft/TypeScript |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 6a93e25585f487ddff9e3996c06d5b869d6e1828 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width