From 534ba8e3642bed31e64036b177ba0e1941032813 Mon Sep 17 00:00:00 2001 From: Matt Vague Date: Wed, 19 Oct 2022 12:33:48 -0700 Subject: [PATCH 1/6] WIP Bring back discriminated union for MathNode --- types/index.d.ts | 170 ++++++++++++++++++++++++++++------------------- 1 file changed, 103 insertions(+), 67 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 4600ceb7ef..5c1e20c929 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -162,73 +162,73 @@ declare namespace math { } interface NodeCtor { - new (): MathNode + new (): BaseNode } - interface AccessorNode extends MathNode { + interface AccessorNode extends BaseNode { type: 'AccessorNode' isAccessorNode: true - object: MathNode + object: BaseNode index: IndexNode name: string } interface AccessorNodeCtor { - new (object: MathNode, index: IndexNode): AccessorNode + new (object: BaseNode, index: IndexNode): AccessorNode } - interface ArrayNode extends MathNode { + interface ArrayNode extends BaseNode { type: 'ArrayNode' isArrayNode: true - items: MathNode[] + items: BaseNode[] } interface ArrayNodeCtor { - new (items: MathNode[]): ArrayNode + new (items: BaseNode[]): ArrayNode } - interface AssignmentNode extends MathNode { + interface AssignmentNode extends BaseNode { type: 'AssignmentNode' isAssignmentNode: true object: SymbolNode | AccessorNode index: IndexNode | null - value: MathNode + value: BaseNode name: string } interface AssignmentNodeCtor { - new (object: SymbolNode, value: MathNode): AssignmentNode + new (object: SymbolNode, value: BaseNode): AssignmentNode new ( object: SymbolNode | AccessorNode, index: IndexNode, - value: MathNode + value: BaseNode ): AssignmentNode } - interface BlockNode extends MathNode { + interface BlockNode extends BaseNode { type: 'BlockNode' isBlockNode: true - blocks: Array<{ node: MathNode; visible: boolean }> + blocks: Array<{ node: BaseNode; visible: boolean }> } interface BlockNodeCtor { new ( - arr: Array<{ node: MathNode } | { node: MathNode; visible: boolean }> + arr: Array<{ node: BaseNode } | { node: BaseNode; visible: boolean }> ): BlockNode } - interface ConditionalNode extends MathNode { + interface ConditionalNode extends BaseNode { type: 'ConditionalNode' isConditionalNode: boolean - condition: MathNode - trueExpr: MathNode - falseExpr: MathNode + condition: BaseNode + trueExpr: BaseNode + falseExpr: BaseNode } interface ConditionalNodeCtor { new ( - condition: MathNode, - trueExpr: MathNode, - falseExpr: MathNode + condition: BaseNode, + trueExpr: BaseNode, + falseExpr: BaseNode ): ConditionalNode } - interface ConstantNode extends MathNode { + interface ConstantNode extends BaseNode { type: 'ConstantNode' isConstantNode: true // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -239,47 +239,47 @@ declare namespace math { new (constant: number): ConstantNode } - interface FunctionAssignmentNode extends MathNode { + interface FunctionAssignmentNode extends BaseNode { type: 'FunctionAssignmentNode' isFunctionAssignmentNode: true name: string params: string[] - expr: MathNode + expr: BaseNode } interface FunctionAssignmentNodeCtor { - new (name: string, params: string[], expr: MathNode): FunctionAssignmentNode + new (name: string, params: string[], expr: BaseNode): FunctionAssignmentNode } - interface FunctionNode extends MathNode { + interface FunctionNode extends BaseNode { type: 'FunctionNode' isFunctionNode: true fn: SymbolNode - args: MathNode[] + args: BaseNode[] } interface FunctionNodeCtor { - new (fn: MathNode | string, args: MathNode[]): FunctionNode + new (fn: BaseNode | string, args: BaseNode[]): FunctionNode // eslint-disable-next-line @typescript-eslint/no-explicit-any onUndefinedFunction: (name: string) => any } - interface IndexNode extends MathNode { + interface IndexNode extends BaseNode { type: 'IndexNode' isIndexNode: true - dimensions: MathNode[] + dimensions: BaseNode[] dotNotation: boolean } interface IndexNodeCtor { - new (dimensions: MathNode[]): IndexNode - new (dimensions: MathNode[], dotNotation: boolean): IndexNode + new (dimensions: BaseNode[]): IndexNode + new (dimensions: BaseNode[], dotNotation: boolean): IndexNode } - interface ObjectNode extends MathNode { + interface ObjectNode extends BaseNode { type: 'ObjectNode' isObjectNode: true - properties: Record + properties: Record } interface ObjectNodeCtor { - new (properties: Record): ObjectNode + new (properties: Record): ObjectNode } type OperatorNodeMap = { @@ -321,8 +321,8 @@ declare namespace math { interface OperatorNode< TOp extends OperatorNodeMap[TFn] = never, TFn extends OperatorNodeFn = never, - TArgs extends MathNode[] = MathNode[] - > extends MathNode { + TArgs extends BaseNode[] = BaseNode[] + > extends BaseNode { type: 'OperatorNode' isOperatorNode: true op: TOp @@ -333,11 +333,11 @@ declare namespace math { isBinary(): boolean } - interface OperatorNodeCtor extends MathNode { + interface OperatorNodeCtor extends BaseNode { new < TOp extends OperatorNodeMap[TFn], TFn extends OperatorNodeFn, - TArgs extends MathNode[] + TArgs extends BaseNode[] >( op: TOp, fn: TFn, @@ -345,40 +345,40 @@ declare namespace math { implicit?: boolean ): OperatorNode } - interface ParenthesisNode - extends MathNode { + interface ParenthesisNode + extends BaseNode { type: 'ParenthesisNode' isParenthesisNode: true content: TContent } interface ParenthesisNodeCtor { - new ( + new ( content: TContent ): ParenthesisNode } - interface RangeNode extends MathNode { + interface RangeNode extends BaseNode { type: 'RangeNode' isRangeNode: true - start: MathNode - end: MathNode - step: MathNode | null + start: BaseNode + end: BaseNode + step: BaseNode | null } interface RangeNodeCtor { - new (start: MathNode, end: MathNode, step?: MathNode): RangeNode + new (start: BaseNode, end: BaseNode, step?: BaseNode): RangeNode } - interface RelationalNode extends MathNode { + interface RelationalNode extends BaseNode { type: 'RelationalNode' isRelationalNode: true conditionals: string[] - params: MathNode[] + params: BaseNode[] } interface RelationalNodeCtor { - new (conditionals: string[], params: MathNode[]): RelationalNode + new (conditionals: string[], params: BaseNode[]): RelationalNode } - interface SymbolNode extends MathNode { + interface SymbolNode extends BaseNode { type: 'SymbolNode' isSymbolNode: true name: string @@ -389,8 +389,44 @@ declare namespace math { onUndefinedSymbol: (name: string) => any } + interface MathNodeTypes { + AccessorNode: AccessorNode + ArrayNode: ArrayNode + AssignmentNode: AssignmentNode + BlockNode: BlockNode + ConditionalNode: ConditionalNode + ConstantNode: ConstantNode + FunctionAssignmentNode: FunctionAssignmentNode + FunctionNode: FunctionNode + IndexNode: IndexNode + ObjectNode: ObjectNode + OperatorNode: OperatorNode + ParenthesisNode: ParenthesisNode + RangeNode: RangeNode + RelationalNode: RelationalNode + SymbolNode: SymbolNode + } + + /** + * Discriminated union describing all registered node types + * + * Deriving this union from MathNodeTypes makes the union extensible for implementors using `declare module 'mathjs'` + * + * e.g. + * + * declare module 'mathjs' { + * interface MyNode extends BaseNode { + * } + + * interface MathNodeTypes { + * MyNode: MyNode + * } + * } + */ + type MathNode = MathNodeTypes[keyof MathNodeTypes] + /** - * @deprecated since version 11.3. Prefer `MathNode` instead + * @deprecated since version 11.3. Prefer `BaseNode` instead */ type MathNodeCommon = MathNode @@ -3855,7 +3891,7 @@ declare namespace math { evaluate(scope?: any): any } - interface MathNode { + interface BaseNode { isNode: true comment: string type: string @@ -3901,9 +3937,9 @@ declare namespace math { * ``` * var node = math.parse('x^2 + x/4 + 3*y'); * var filtered = node.filter(function (node) { - * return node.isSymbolMathNode && node.name == 'x'; + * return node.isSymbolNode && node.name == 'x'; * }); - * // returns an array with two entries: two SymbolMathNodes 'x' + * // returns an array with two entries: two SymbolNodes 'x' * ``` * * The callback function is called as callback(node: MathNode, path: @@ -3967,13 +4003,13 @@ declare namespace math { * and must return a MathNode. Parameter path is a string containing a * relative JSON Path. * - * For example, to replace all nodes of type SymbolMathNode having name - * ‘x’ with a ConstantMathNode with value 3: + * For example, to replace all nodes of type SymbolNode having name + * ‘x’ with a ConstantNode with value 3: * ```js * var node = math.parse('x^2 + 5*x'); * var transformed = node.transform(function (node, path, parent) { - * if (node.SymbolMathNode && node.name == 'x') { - * return new math.expression.node.ConstantMathNode(3); + * if (node.SymbolNode && node.name == 'x') { + * return new math.expression.node.ConstantNode(3); * } * else { * return node; @@ -4001,18 +4037,18 @@ declare namespace math { * var node = math.parse('3 * x + 2'); * node.traverse(function (node, path, parent) { * switch (node.type) { - * case 'OperatorMathNode': console.log(node.type, node.op); break; - * case 'ConstantMathNode': console.log(node.type, node.value); break; - * case 'SymbolMathNode': console.log(node.type, node.name); break; + * case 'OperatorNode': console.log(node.type, node.op); break; + * case 'ConstantNode': console.log(node.type, node.value); break; + * case 'SymbolNode': console.log(node.type, node.name); break; * default: console.log(node.type); * } * }); * // outputs: - * // OperatorMathNode + - * // OperatorMathNode * - * // ConstantMathNode 3 - * // SymbolMathNode x - * // ConstantMathNode 2 + * // OperatorNode + + * // OperatorNode * + * // ConstantNode 3 + * // SymbolNode x + * // ConstantNode 2 * ``` */ traverse( From 0fb3bf7180c06cb1b60c807d45e3011ca3e5d0f2 Mon Sep 17 00:00:00 2001 From: Chris Chudzicki Date: Sat, 22 Oct 2022 16:22:22 -0400 Subject: [PATCH 2/6] lint ts files in test dir --- .eslintrc.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 938d5959c5..0563ab4a74 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -33,7 +33,7 @@ module.exports = { } }, { - files: ['types/*.ts'], + files: ['types/*.ts', 'test/**/*.ts'], extends: [ 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended' // this should come last From 8928cb375b6403c7d7f16f364ec81da9f2ee74f7 Mon Sep 17 00:00:00 2001 From: Chris Chudzicki Date: Sat, 22 Oct 2022 16:23:22 -0400 Subject: [PATCH 3/6] change operatornode generic defaults --- test/typescript-tests/nodeExtensions.ts | 43 ++++++++++++++++++ test/typescript-tests/testTypes.ts | 58 +++++-------------------- types/index.d.ts | 8 ++-- 3 files changed, 57 insertions(+), 52 deletions(-) create mode 100644 test/typescript-tests/nodeExtensions.ts diff --git a/test/typescript-tests/nodeExtensions.ts b/test/typescript-tests/nodeExtensions.ts new file mode 100644 index 0000000000..e06697c6e8 --- /dev/null +++ b/test/typescript-tests/nodeExtensions.ts @@ -0,0 +1,43 @@ +import { expectTypeOf } from 'expect-type' +import { MathNode, MathNodeCommon, ConstantNode, Node } from 'mathjs' + +declare module 'mathjs' { + type MyNode = BaseNode + + interface MathNodeTypes { + MyNode: MyNode + } +} + +/* +MathNode examples +*/ +{ + class CustomNode extends Node { + a: MathNode + constructor(a: MathNode) { + super() + this.a = a + } + } + + // Basic node + const instance1 = new Node() + + // Built-in subclass of Node + const instance2 = new ConstantNode(2) + + // Custom subclass of node + const instance3 = new CustomNode(new ConstantNode(2)) + + expectTypeOf(instance1).toMatchTypeOf() + expectTypeOf(instance1).toMatchTypeOf() + + expectTypeOf(instance2).toMatchTypeOf() + expectTypeOf(instance2).toMatchTypeOf() + expectTypeOf(instance2).toMatchTypeOf() + + expectTypeOf(instance3).toMatchTypeOf() + expectTypeOf(instance3).toMatchTypeOf() + expectTypeOf(instance3).toMatchTypeOf() +} diff --git a/test/typescript-tests/testTypes.ts b/test/typescript-tests/testTypes.ts index 3eb6f8f3e9..299a0430e6 100644 --- a/test/typescript-tests/testTypes.ts +++ b/test/typescript-tests/testTypes.ts @@ -32,8 +32,6 @@ import { Matrix, ObjectNode, OperatorNode, - OperatorNodeFn, - OperatorNodeOp, ParenthesisNode, PolarCoordinates, QRDecomposition, @@ -41,10 +39,9 @@ import { SimplifyRule, SLUDecomposition, SymbolNode, - MathNodeCommon, Unit, - Node, isSymbolNode, + BaseNode, } from 'mathjs' import * as assert from 'assert' import { expectTypeOf } from 'expect-type' @@ -1089,16 +1086,16 @@ Transform examples { const math = create(all, {}) { - const myTransform1 = (node: MathNode): OperatorNode<'+', 'add'> => + const myTransform1 = (node: MathNode): OperatorNode<'add', '+'> => new OperatorNode('+', 'add', [node, new ConstantNode(1)]) const myTransform2 = ( - node: OperatorNode<'+', 'add'> - ): OperatorNode<'-', 'subtract'> => + node: OperatorNode<'add', '+'> + ): OperatorNode<'subtract', '-'> => new OperatorNode('-', 'subtract', [node, new ConstantNode(5)]) expectTypeOf( math.parse('sqrt(3^2 + 4^2)').transform(myTransform1) - ).toMatchTypeOf>() + ).toMatchTypeOf>() assert.deepStrictEqual( math.parse('sqrt(3^2 + 4^2)').transform(myTransform1).toString(), @@ -1110,7 +1107,7 @@ Transform examples .parse('sqrt(3^2 + 4^2)') .transform(myTransform1) .transform(myTransform2) - ).toMatchTypeOf>() + ).toMatchTypeOf>() assert.deepStrictEqual( math @@ -1845,7 +1842,7 @@ Function round examples new math.ConstantNode(3), new math.SymbolNode('x'), ]) - ).toMatchTypeOf>() + ).toMatchTypeOf>() expectTypeOf(new math.ConstantNode(1).clone()).toMatchTypeOf() expectTypeOf( @@ -1854,7 +1851,7 @@ Function round examples new math.SymbolNode('x'), ]).clone() ).toMatchTypeOf< - OperatorNode<'*', 'multiply', (ConstantNode | SymbolNode)[]> + OperatorNode<'multiply', '*', (ConstantNode | SymbolNode)[]> >() expectTypeOf( @@ -1866,7 +1863,7 @@ Function round examples new math.SymbolNode('x'), ]).cloneDeep() ).toMatchTypeOf< - OperatorNode<'+', 'unaryPlus', (ConstantNode | SymbolNode)[]> + OperatorNode<'unaryPlus', '+', (ConstantNode | SymbolNode)[]> >() expectTypeOf( @@ -2225,9 +2222,7 @@ Factory Test expectTypeOf(x).toMatchTypeOf() } if (math.isOperatorNode(x)) { - expectTypeOf(x).toMatchTypeOf< - OperatorNode - >() + expectTypeOf(x).toMatchTypeOf() } if (math.isParenthesisNode(x)) { expectTypeOf(x).toMatchTypeOf() @@ -2308,36 +2303,3 @@ Random examples MathJsChain >() } - -/* -MathNode examples -*/ -{ - class CustomNode extends Node { - a: MathNode - constructor(a: MathNode) { - super() - this.a = a - } - } - - // Basic node - const instance1 = new Node() - - // Built-in subclass of Node - const instance2 = new ConstantNode(2) - - // Custom subclass of node - const instance3 = new CustomNode(new ConstantNode(2)) - - expectTypeOf(instance1).toMatchTypeOf() - expectTypeOf(instance1).toMatchTypeOf() - - expectTypeOf(instance2).toMatchTypeOf() - expectTypeOf(instance2).toMatchTypeOf() - expectTypeOf(instance2).toMatchTypeOf() - - expectTypeOf(instance3).toMatchTypeOf() - expectTypeOf(instance3).toMatchTypeOf() - expectTypeOf(instance3).toMatchTypeOf() -} diff --git a/types/index.d.ts b/types/index.d.ts index 5c1e20c929..27e0c29749 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -319,8 +319,8 @@ declare namespace math { type OperatorNodeFn = keyof OperatorNodeMap interface OperatorNode< - TOp extends OperatorNodeMap[TFn] = never, - TFn extends OperatorNodeFn = never, + TFn extends OperatorNodeFn = OperatorNodeFn, + TOp extends OperatorNodeMap[TFn] = OperatorNodeMap[TFn], TArgs extends BaseNode[] = BaseNode[] > extends BaseNode { type: 'OperatorNode' @@ -343,7 +343,7 @@ declare namespace math { fn: TFn, args: TArgs, implicit?: boolean - ): OperatorNode + ): OperatorNode } interface ParenthesisNode extends BaseNode { @@ -3187,7 +3187,7 @@ declare namespace math { isOperatorNode( x: unknown - ): x is OperatorNode + ): x is OperatorNode isParenthesisNode(x: unknown): x is ParenthesisNode From ef722379a10c314b078c783cf7b48a505be449b7 Mon Sep 17 00:00:00 2001 From: Chris Chudzicki Date: Sat, 22 Oct 2022 16:29:11 -0400 Subject: [PATCH 4/6] remove TOp type generic type --- test/typescript-tests/testTypes.ts | 20 ++++++++------------ types/index.d.ts | 9 +++------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/test/typescript-tests/testTypes.ts b/test/typescript-tests/testTypes.ts index 299a0430e6..e31c2bf0ee 100644 --- a/test/typescript-tests/testTypes.ts +++ b/test/typescript-tests/testTypes.ts @@ -1086,16 +1086,16 @@ Transform examples { const math = create(all, {}) { - const myTransform1 = (node: MathNode): OperatorNode<'add', '+'> => + const myTransform1 = (node: MathNode): OperatorNode<'add'> => new OperatorNode('+', 'add', [node, new ConstantNode(1)]) const myTransform2 = ( - node: OperatorNode<'add', '+'> - ): OperatorNode<'subtract', '-'> => + node: OperatorNode<'add'> + ): OperatorNode<'subtract'> => new OperatorNode('-', 'subtract', [node, new ConstantNode(5)]) expectTypeOf( math.parse('sqrt(3^2 + 4^2)').transform(myTransform1) - ).toMatchTypeOf>() + ).toMatchTypeOf>() assert.deepStrictEqual( math.parse('sqrt(3^2 + 4^2)').transform(myTransform1).toString(), @@ -1107,7 +1107,7 @@ Transform examples .parse('sqrt(3^2 + 4^2)') .transform(myTransform1) .transform(myTransform2) - ).toMatchTypeOf>() + ).toMatchTypeOf>() assert.deepStrictEqual( math @@ -1842,7 +1842,7 @@ Function round examples new math.ConstantNode(3), new math.SymbolNode('x'), ]) - ).toMatchTypeOf>() + ).toMatchTypeOf>() expectTypeOf(new math.ConstantNode(1).clone()).toMatchTypeOf() expectTypeOf( @@ -1850,9 +1850,7 @@ Function round examples new math.ConstantNode(3), new math.SymbolNode('x'), ]).clone() - ).toMatchTypeOf< - OperatorNode<'multiply', '*', (ConstantNode | SymbolNode)[]> - >() + ).toMatchTypeOf>() expectTypeOf( new math.ConstantNode(1).cloneDeep() @@ -1862,9 +1860,7 @@ Function round examples new math.ConstantNode(3), new math.SymbolNode('x'), ]).cloneDeep() - ).toMatchTypeOf< - OperatorNode<'unaryPlus', '+', (ConstantNode | SymbolNode)[]> - >() + ).toMatchTypeOf>() expectTypeOf( math.clone(new math.ConstantNode(1)) diff --git a/types/index.d.ts b/types/index.d.ts index 27e0c29749..90c271a0ad 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -320,12 +320,11 @@ declare namespace math { interface OperatorNode< TFn extends OperatorNodeFn = OperatorNodeFn, - TOp extends OperatorNodeMap[TFn] = OperatorNodeMap[TFn], TArgs extends BaseNode[] = BaseNode[] > extends BaseNode { type: 'OperatorNode' isOperatorNode: true - op: TOp + op: OperatorNodeMap[TFn] fn: TFn args: TArgs implicit: boolean @@ -343,7 +342,7 @@ declare namespace math { fn: TFn, args: TArgs, implicit?: boolean - ): OperatorNode + ): OperatorNode } interface ParenthesisNode extends BaseNode { @@ -3185,9 +3184,7 @@ declare namespace math { isObjectNode(x: unknown): x is ObjectNode - isOperatorNode( - x: unknown - ): x is OperatorNode + isOperatorNode(x: unknown): x is OperatorNode isParenthesisNode(x: unknown): x is ParenthesisNode From bdf864d36b2957e25cd57c44e9e042b842a11a5d Mon Sep 17 00:00:00 2001 From: Chris Chudzicki Date: Sat, 22 Oct 2022 16:53:26 -0400 Subject: [PATCH 5/6] add a test for discrimination --- test/typescript-tests/nodeExtensions.ts | 37 +++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/test/typescript-tests/nodeExtensions.ts b/test/typescript-tests/nodeExtensions.ts index e06697c6e8..dc8d176b7b 100644 --- a/test/typescript-tests/nodeExtensions.ts +++ b/test/typescript-tests/nodeExtensions.ts @@ -1,9 +1,18 @@ import { expectTypeOf } from 'expect-type' -import { MathNode, MathNodeCommon, ConstantNode, Node } from 'mathjs' - +import { + MathNode, + BaseNode, + MathNodeCommon, + ConstantNode, + Node, + FunctionAssignmentNode, +} from 'mathjs' + +interface MyNode extends BaseNode { + type: 'MyNode' + a: MathNode +} declare module 'mathjs' { - type MyNode = BaseNode - interface MathNodeTypes { MyNode: MyNode } @@ -13,31 +22,31 @@ declare module 'mathjs' { MathNode examples */ { - class CustomNode extends Node { + class CustomNode extends Node implements MyNode { a: MathNode + type: 'MyNode' constructor(a: MathNode) { super() this.a = a } } - // Basic node - const instance1 = new Node() - // Built-in subclass of Node - const instance2 = new ConstantNode(2) + const instance1 = new ConstantNode(2) // Custom subclass of node - const instance3 = new CustomNode(new ConstantNode(2)) + const instance2 = new CustomNode(new ConstantNode(2)) expectTypeOf(instance1).toMatchTypeOf() expectTypeOf(instance1).toMatchTypeOf() + expectTypeOf(instance1).toMatchTypeOf() expectTypeOf(instance2).toMatchTypeOf() expectTypeOf(instance2).toMatchTypeOf() - expectTypeOf(instance2).toMatchTypeOf() + expectTypeOf(instance2).toMatchTypeOf() - expectTypeOf(instance3).toMatchTypeOf() - expectTypeOf(instance3).toMatchTypeOf() - expectTypeOf(instance3).toMatchTypeOf() + let instance3: MathNode + if (instance3.type === 'FunctionAssignmentNode') { + expectTypeOf(instance3).toMatchTypeOf() + } } From 899115db1c686cca47215362f6dc3e1804a81815 Mon Sep 17 00:00:00 2001 From: Chris Chudzicki Date: Wed, 2 Nov 2022 21:50:08 -0400 Subject: [PATCH 6/6] revert to old operatornode typeargs --- test/typescript-tests/testTypes.ts | 26 +++++++++++++++++--------- types/index.d.ts | 13 ++++++++----- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/test/typescript-tests/testTypes.ts b/test/typescript-tests/testTypes.ts index e31c2bf0ee..1393667ebd 100644 --- a/test/typescript-tests/testTypes.ts +++ b/test/typescript-tests/testTypes.ts @@ -32,6 +32,8 @@ import { Matrix, ObjectNode, OperatorNode, + OperatorNodeFn, + OperatorNodeOp, ParenthesisNode, PolarCoordinates, QRDecomposition, @@ -1086,16 +1088,16 @@ Transform examples { const math = create(all, {}) { - const myTransform1 = (node: MathNode): OperatorNode<'add'> => + const myTransform1 = (node: MathNode): OperatorNode<'+', 'add'> => new OperatorNode('+', 'add', [node, new ConstantNode(1)]) const myTransform2 = ( - node: OperatorNode<'add'> - ): OperatorNode<'subtract'> => + node: OperatorNode<'+', 'add'> + ): OperatorNode<'-', 'subtract'> => new OperatorNode('-', 'subtract', [node, new ConstantNode(5)]) expectTypeOf( math.parse('sqrt(3^2 + 4^2)').transform(myTransform1) - ).toMatchTypeOf>() + ).toMatchTypeOf>() assert.deepStrictEqual( math.parse('sqrt(3^2 + 4^2)').transform(myTransform1).toString(), @@ -1107,7 +1109,7 @@ Transform examples .parse('sqrt(3^2 + 4^2)') .transform(myTransform1) .transform(myTransform2) - ).toMatchTypeOf>() + ).toMatchTypeOf>() assert.deepStrictEqual( math @@ -1842,7 +1844,7 @@ Function round examples new math.ConstantNode(3), new math.SymbolNode('x'), ]) - ).toMatchTypeOf>() + ).toMatchTypeOf>() expectTypeOf(new math.ConstantNode(1).clone()).toMatchTypeOf() expectTypeOf( @@ -1850,7 +1852,9 @@ Function round examples new math.ConstantNode(3), new math.SymbolNode('x'), ]).clone() - ).toMatchTypeOf>() + ).toMatchTypeOf< + OperatorNode<'*', 'multiply', (ConstantNode | SymbolNode)[]> + >() expectTypeOf( new math.ConstantNode(1).cloneDeep() @@ -1860,7 +1864,9 @@ Function round examples new math.ConstantNode(3), new math.SymbolNode('x'), ]).cloneDeep() - ).toMatchTypeOf>() + ).toMatchTypeOf< + OperatorNode<'+', 'unaryPlus', (ConstantNode | SymbolNode)[]> + >() expectTypeOf( math.clone(new math.ConstantNode(1)) @@ -2218,7 +2224,9 @@ Factory Test expectTypeOf(x).toMatchTypeOf() } if (math.isOperatorNode(x)) { - expectTypeOf(x).toMatchTypeOf() + expectTypeOf(x).toMatchTypeOf< + OperatorNode + >() } if (math.isParenthesisNode(x)) { expectTypeOf(x).toMatchTypeOf() diff --git a/types/index.d.ts b/types/index.d.ts index 90c271a0ad..2e3d6dd54f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -319,12 +319,13 @@ declare namespace math { type OperatorNodeFn = keyof OperatorNodeMap interface OperatorNode< - TFn extends OperatorNodeFn = OperatorNodeFn, + TOp extends OperatorNodeMap[TFn] = never, + TFn extends OperatorNodeFn = never, TArgs extends BaseNode[] = BaseNode[] > extends BaseNode { type: 'OperatorNode' isOperatorNode: true - op: OperatorNodeMap[TFn] + op: TOp fn: TFn args: TArgs implicit: boolean @@ -342,7 +343,7 @@ declare namespace math { fn: TFn, args: TArgs, implicit?: boolean - ): OperatorNode + ): OperatorNode } interface ParenthesisNode extends BaseNode { @@ -399,7 +400,7 @@ declare namespace math { FunctionNode: FunctionNode IndexNode: IndexNode ObjectNode: ObjectNode - OperatorNode: OperatorNode + OperatorNode: OperatorNode ParenthesisNode: ParenthesisNode RangeNode: RangeNode RelationalNode: RelationalNode @@ -3184,7 +3185,9 @@ declare namespace math { isObjectNode(x: unknown): x is ObjectNode - isOperatorNode(x: unknown): x is OperatorNode + isOperatorNode( + x: unknown + ): x is OperatorNode isParenthesisNode(x: unknown): x is ParenthesisNode