Skip to content

Add math intrinsic types #48198

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
215 changes: 191 additions & 24 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6222,6 +6222,7 @@ export const enum TypeFlags {
Reserved1 = 1 << 29, // Used by union/intersection type construction
/** @internal */
Reserved2 = 1 << 30, // Used by union/intersection type construction
Calculation = 1 << 31, // Math type

/** @internal */
AnyOrUnknown = Any | Unknown,
Expand All @@ -6239,7 +6240,7 @@ export const enum TypeFlags {
/** @internal */
Intrinsic = Any | Unknown | String | Number | BigInt | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
StringLike = String | StringLiteral | TemplateLiteral | StringMapping,
NumberLike = Number | NumberLiteral | Enum,
NumberLike = Number | NumberLiteral | Enum | Calculation,
BigIntLike = BigInt | BigIntLiteral,
BooleanLike = Boolean | BooleanLiteral,
EnumLike = Enum | EnumLiteral,
Expand All @@ -6255,7 +6256,7 @@ export const enum TypeFlags {
StructuredType = Object | Union | Intersection,
TypeVariable = TypeParameter | IndexedAccess,
InstantiableNonPrimitive = TypeVariable | Conditional | Substitution,
InstantiablePrimitive = Index | TemplateLiteral | StringMapping,
InstantiablePrimitive = Index | TemplateLiteral | StringMapping | Calculation,
Instantiable = InstantiableNonPrimitive | InstantiablePrimitive,
StructuredOrInstantiable = StructuredType | Instantiable,
/** @internal */
Expand Down Expand Up @@ -6826,6 +6827,11 @@ export interface StringMappingType extends InstantiableType {
type: Type;
}

export interface CalculationType extends InstantiableType {
symbol: Symbol;
types: [Type] | [Type, Type];
}

// Type parameter substitution (TypeFlags.Substitution)
// Substitution types are created for type parameters or indexed access types that occur in the
// true branch of a conditional type. For example, in 'T extends string ? Foo<T> : Bar<T>', the
Expand Down
7 changes: 7 additions & 0 deletions src/harness/fourslashInterfaceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,13 @@ export namespace Completion {
typeEntry("Lowercase"),
typeEntry("Capitalize"),
typeEntry("Uncapitalize"),
typeEntry("Floor"),
typeEntry("Ceil"),
typeEntry("Round"),
typeEntry("Add"),
typeEntry("Subtract"),
typeEntry("Multiply"),
typeEntry("Divide"),
typeEntry("NoInfer"),
interfaceEntry("ThisType"),
varEntry("ArrayBuffer"),
Expand Down
35 changes: 35 additions & 0 deletions src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,41 @@ type Capitalize<S extends string> = intrinsic;
*/
type Uncapitalize<S extends string> = intrinsic;

/**
* Convert a number literal type to an integer by flooring it
*/
type Floor<N extends number> = intrinsic;

/**
* Convert a number literal type to an integer by ceiling it
*/
type Ceil<N extends number> = intrinsic;

/**
* Convert a number literal type to integer by rounding it
*/
type Round<N extends number> = intrinsic;

/**
* Add two literal numbers
*/
type Add<M extends number, N extends number> = intrinsic;

/**
* Subtract two literal numbers
*/
type Subtract<M extends number, N extends number> = intrinsic;

/**
* Multiply two literal numbers
*/
type Multiply<M extends number, N extends number> = intrinsic;

/**
* Divide two literal numbers
*/
type Divide<M extends number, N extends number> = intrinsic;

/**
* Marker for non-inference type position
*/
Expand Down
20 changes: 15 additions & 5 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6549,13 +6549,14 @@ declare namespace ts {
NonPrimitive = 67108864,
TemplateLiteral = 134217728,
StringMapping = 268435456,
Calculation = -2147483648,
Literal = 2944,
Unit = 109472,
Freshable = 2976,
StringOrNumberLiteral = 384,
PossiblyFalsy = 117724,
StringLike = 402653316,
NumberLike = 296,
NumberLike = -2147483352,
BigIntLike = 2112,
BooleanLike = 528,
EnumLike = 1056,
Expand All @@ -6565,10 +6566,10 @@ declare namespace ts {
StructuredType = 3670016,
TypeVariable = 8650752,
InstantiableNonPrimitive = 58982400,
InstantiablePrimitive = 406847488,
Instantiable = 465829888,
StructuredOrInstantiable = 469499904,
Narrowable = 536624127,
InstantiablePrimitive = -1740636160,
Instantiable = -1681653760,
StructuredOrInstantiable = -1677983744,
Narrowable = -1610859521,
}
type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression;
interface Type {
Expand Down Expand Up @@ -6764,6 +6765,15 @@ declare namespace ts {
symbol: Symbol;
type: Type;
}
interface CalculationType extends InstantiableType {
symbol: Symbol;
types: [
Type,
] | [
Type,
Type,
];
}
interface SubstitutionType extends InstantiableType {
objectFlags: ObjectFlags;
baseType: Type;
Expand Down
164 changes: 163 additions & 1 deletion tests/baselines/reference/intrinsicTypes.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,28 @@ intrinsicTypes.ts(42,5): error TS2322: Type 'string' is not assignable to type '
intrinsicTypes.ts(43,5): error TS2322: Type 'Uppercase<T>' is not assignable to type 'Uppercase<U>'.
Type 'T' is not assignable to type 'U'.
'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'string'.
intrinsicTypes.ts(61,18): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(76,17): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(77,20): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(78,18): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(93,22): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(94,25): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(95,23): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(110,22): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(111,25): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(112,23): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(127,20): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(128,23): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(129,21): error TS2344: Type 'string' does not satisfy the constraint 'number'.
intrinsicTypes.ts(147,5): error TS2322: Type 'number' is not assignable to type 'Add<T, U>'.
intrinsicTypes.ts(148,5): error TS2322: Type 'Multiply<T, U>' is not assignable to type 'Add<T, U>'.
Type 'number' is not assignable to type 'Add<T, U>'.
intrinsicTypes.ts(149,5): error TS2322: Type 'number' is not assignable to type 'Multiply<T, U>'.
intrinsicTypes.ts(150,5): error TS2322: Type 'Add<T, U>' is not assignable to type 'Multiply<T, U>'.
Type 'number' is not assignable to type 'Multiply<T, U>'.


==== intrinsicTypes.ts (8 errors) ====
==== intrinsicTypes.ts (25 errors) ====
type TU1 = Uppercase<'hello'>; // "HELLO"
type TU2 = Uppercase<'foo' | 'bar'>; // "FOO" | "BAR"
type TU3 = Uppercase<string>; // Uppercase<string>
Expand Down Expand Up @@ -83,4 +102,147 @@ intrinsicTypes.ts(43,5): error TS2322: Type 'Uppercase<T>' is not assignable to
function foo4<U extends string>(x: Uppercase<U>) {
return foo3(x);
}

type TI1 = Floor<3.5>; // 3
type TI2 = Floor<2.5 | 3.4>; // 2 | 3
type TI3 = Floor<number>; // number
type TI4 = Floor<any>; // any
type TI5 = Floor<never>; // never
type TI6 = Floor<'42'>; // Error
~~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.

type TA1 = Add<4, 2>; // 6
type TA2L = Add<4 | 5, 2>; // 6 | 7
type TA2R = Add<4, 2 | 3>; // 6 | 7
type TA2LR = Add<4 | 5, 2 | 3>; // 6 | 7 | 8
type TA3L = Add<number, 2>; // number
type TA3R = Add<4, number>; // number
type TA3LR = Add<number, number>; // number
type TA4L = Add<any, 2>; // any
type TA4R = Add<4, any>; // any
type TA4LR = Add<any, any>; // any
type TA5L = Add<never, 2>; // never
type TA5R = Add<4, never>; // never
type TA5LR = Add<never, never>; // never
type TA6L = Add<'4', 2>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TA6R = Add<4, '2'>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TA6LR = Add<'4', '2'>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.

type TS1 = Subtract<4, 2>; // 2
type TS2L = Subtract<4 | 5, 2>; // 2 | 3
type TS2R = Subtract<4, 2 | 3>; // 2 | 1
type TS2LR = Subtract<4 | 5, 2 | 3>; // 2 | 1 | 3
type TS3L = Subtract<number, 2>; // number
type TS3R = Subtract<4, number>; // number
type TS3LR = Subtract<number, number>; // number
type TS4L = Subtract<any, 2>; // any
type TS4R = Subtract<4, any>; // any
type TS4LR = Subtract<any, any>; // any
type TS5L = Subtract<never, 2>; // never
type TS5R = Subtract<4, never>; // never
type TS5LR = Subtract<never, never>; // never
type TS6L = Subtract<'4', 2>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TS6R = Subtract<4, '2'>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TS6LR = Subtract<'4', '2'>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.

type TM1 = Multiply<4, 2>; // 8
type TM2L = Multiply<4 | 5, 2>; // 8 | 10
type TM2R = Multiply<4, 2 | 3>; // 8 | 12
type TM2LR = Multiply<4 | 5, 2 | 3>; // 8 | 12 | 10 | 15
type TM3L = Multiply<number, 2>; // number
type TM3R = Multiply<4, number>; // number
type TM3LR = Multiply<number, number>; // number
type TM4L = Multiply<any, 2>; // any
type TM4R = Multiply<4, any>; // any
type TM4LR = Multiply<any, any>; // any
type TM5L = Multiply<never, 2>; // never
type TM5R = Multiply<4, never>; // never
type TM5LR = Multiply<never, never>; // never
type TM6L = Multiply<'4', 2>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TM6R = Multiply<4, '2'>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TM6LR = Multiply<'4', '2'>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.

type TD1 = Divide<4, 2>; // 2
type TD2L = Divide<4 | 5, 2>; // 2 | 2.5
type TD2R = Divide<4, 2 | 4>; // 2 | 1
type TD2LR = Divide<4 | 5, 2 | 4>; // 2 | 1 | 2.5 | 1.25
type TD3L = Divide<number, 2>; // number
type TD3R = Divide<4, number>; // number
type TD3LR = Divide<number, number>; // number
type TD4L = Divide<any, 2>; // any
type TD4R = Divide<4, any>; // any
type TD4LR = Divide<any, any>; // any
type TD5L = Divide<never, 2>; // never
type TD5R = Divide<4, never>; // never
type TD5LR = Divide<never, never>; // never
type TD6L = Divide<'4', 2>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TD6R = Divide<4, '2'>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TD6LR = Divide<'4', '2'>; // Error
~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'number'.
type TD7 = Divide<1, 0>; // never

type TIX1<S extends number> = Floor<S>;
type TIX2 = TIX1<4.2>; // 4
type TAX1<M extends number, N extends number> = Add<M, N>;
type TAX2 = TAX1<4, 2>; // 6
type TSX1<M extends number, N extends number> = Subtract<M, N>;
type TSX2 = TSX1<4, 2>; // 6
type TMX1<M extends number, N extends number> = Multiply<M, N>;
type TMX2 = TMX1<4, 2>; // 8
type TDX1<M extends number, N extends number> = Divide<M, N>;
type TDX2 = TDX1<4, 2>; // 2
type TAMX = Add<2, Multiply<5, 8>> // 42

function foo5<T extends number, U extends T>(s: number, x: Add<T, U>, y: Multiply<T, U>) {
s = x;
s = y;
x = s; // Error
~
!!! error TS2322: Type 'number' is not assignable to type 'Add<T, U>'.
x = y; // Error
~
!!! error TS2322: Type 'Multiply<T, U>' is not assignable to type 'Add<T, U>'.
!!! error TS2322: Type 'number' is not assignable to type 'Add<T, U>'.
y = s; // Error
~
!!! error TS2322: Type 'number' is not assignable to type 'Multiply<T, U>'.
y = x; // Error
~
!!! error TS2322: Type 'Add<T, U>' is not assignable to type 'Multiply<T, U>'.
!!! error TS2322: Type 'number' is not assignable to type 'Multiply<T, U>'.
}

function foo6<T extends 0 | 1>(x: Add<T, 3>) {
let s: 3 | 4 = x;
}

declare function foo7<T extends number>(x: Floor<T>): T;

function foo8<U extends number>(x: Floor<U>) {
return foo7(x);
}

Loading