Subtraction types · Issue #4183 · microsoft/TypeScript (original) (raw)

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 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.

type HTMLDivSpecifics = HTMLDivElement - Element;

Proposal

add a type operator that produces a new type out of 2 given types according to the rules that follow:

This feature would require a new negated type like number ~ string which is a number that cannot take number & string.

As far as the precedence of new type operator, it should go:

  1. intersection &
  2. union |
  3. subtraction -

so that number & boolean | string - string, means ((number & boolean) | string) - string

Generics

type Minus<A, B> = A - B; // yet to be calculated

Primitives

type C = number - number; // {} type C = number - {}; // number type C = {} - number; // error type C = number - string; // error type C = number - 0; // number ~ 0

type C = number | string - boolean; // error type C = number - void | null | undefined; // error

type C = number - any; // {} type C = any - any; // any type C = any - number; // any ~ number type C = any - never; // error; type C = never - any; // error; type C = number - never; // error type C = never - number; // error type C = never - never; // error

type C = number | string - string; // number type C = number - number | string; // {} type C = number | string - {}; // number | string

type C = number & string - boolean; // error type C = number & string - string; // number ~ string

Products

type C = {} - { x: number }; // {} type C = { x: number } - {}; // { x: number } type C = { x: {} } - { x: number }; // error type C = { x: number } - { x: {} }; // { x: number } type C = { x: number } - { y: number }; // { x: number } type C = { x: number } - { x: number }; // {} type C = { x: number | string } - { x: string }; // { x: number } type C = { x: number & string } - { x: string }; // { x: number ~ string } type C = { x: number } - { x: string }; // error

Functions (2 certain signatures)

type C = ((x: number) => string) - ((x: number) => string); // {} type C = ((x: number) => number) - ((x: number) => number); // (x: {}) => number type C = ((x: number | string) => string) - ((x: string) => string); // (x: number) => string type C = ((x: number) => string) - ((x: string) => string); // error type C = ((x: number | string) => string) - (() => string); // error type C = (() => string) - ((x: number) => string); // error

Overloads