Skip to content

Subtraction types #4183

Closed
Closed
@zpdDG4gta8XKpMCd

Description

@zpdDG4gta8XKpMCd

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:

type C = A - B;

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

  • 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
type Minus<A, B> = A - B; // yet to be calculated

Primitives

  • if the left type (minued) isn't a sub-type of the right type (subtrahend) the - operation should result to an type error
  • never and any should be specially handled
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

  • 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
  • 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
  • if applying - on 2 properties of the same name gives {}, the property gets dropped from the resulting type
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)

  • both functions must have the same number of parameters, otherwise it's an error
  • types of corresponding parameters are subject to the - operator
  • types of results must 100% match and should be kept intact, otherwise it's an error
  • if - on 2 parameters gives {} the resulting parameter is {}
  • if all resulting parameters are {} the resulting type is {}
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

  • to be continued...

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.SuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions