Issue 1:
For example, we have interface

interface A {
a: string;
b: number;
c: string;
d: number;
//etc
}

and we want interface which contains all members except {c: string} and includes

{
f: number;
}

Ofcource we can split interface A, but, for example, this interface stored in another npm package.

Another example

interface BemProps {
modifications?: Array<{
[index: string]: boolean;
} | string>;
prefix?: string;
additionalClasses?: string;
}

// we want to pass all HTMLButtonElement valid props except className
// for set className we use bem.
function UiButton(props: BemProps & React.HTMLProps<HTMLButtonElement>) {
return (
<button disabled className={GetBEMClassNames(props) } {...props}>
{props.children}
</button>
);
}

I suggest new keyword 'except' or '!'

Usage

type Props = BemProps & React.HTMLProps<HTMLButtonElement> except { className: string }

or "!"

type Props = BemProps & React.HTMLProps<HTMLButtonElement> ! { className: string }

Issue 2:
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:

intersection &

union |

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