Skip to content

Commit 3d91b20

Browse files
feat: implement const type parameters support with TypeScript 5.0+ compatibility
- Added const modifier detection for type parameters in transformer - Enhanced IRTemplateParameter interface with isConst flag - Updated code generator to include /* const */ comments for const type parameters - Added comprehensive test suite for const type parameter scenarios - Updated documentation with examples and implementation details Technical changes: - Fixed duplicate IRTemplateParameter interface definitions - Added hasConstModifier method for robust const detection - Enhanced template parameter generation in both functions and classes - Added feature detection in AST parser for const type parameters This implementation follows the prototype pattern while providing a cleaner solution with proper type safety and documentation. Tests cover: - Basic const type parameters on functions - Multiple const type parameters - Mixed const and non-const parameters - Const type parameters on class methods - Generic classes with const type parameters - Constrained const type parameters
1 parent 6eb94f7 commit 3d91b20

File tree

7 files changed

+315
-24
lines changed

7 files changed

+315
-24
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919
- feat: Satisfies operator support for type validation without type narrowing (v0.8.6-dev)
2020
- feat: Non-null assertion operator (!) support for nullable type assertions (v0.8.6-dev)
2121
- feat: Definite assignment assertion (!) support for strict property initialization control (v0.8.6-dev)
22+
- feat: Const type parameters support with const modifier detection and C++ comment generation (v0.8.6-dev)
2223
- feat: Object static methods (keys, values, entries, fromEntries, assign, create) in runtime library
2324
- feat: Type assertion (as) expression support in transformer
2425
- feat: ConditionalType, InferType, MappedType, TemplateLiteralType, IndexedAccessType, and TypeQuery handling in SimpleTypeChecker
2526
- feat: AsExpression detection for const assertions with `isConstAssertion` flag propagation
2627
- feat: SatisfiesExpression support with pass-through behavior for compile-time type validation
2728
- feat: NonNullExpression support with pass-through behavior for non-null assertions
2829
- feat: PropertyDeclaration support for definite assignment assertions with standard C++ property generation
30+
- feat: Enhanced IRTemplateParameter interface with isConst flag for TypeScript 5.0+ const type parameter tracking
31+
- feat: Template parameter generation with /* const */ comments for improved code readability
2932

3033
### Fixed
3134

RELEASE_NOTES_v0.8.x.md

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -624,19 +624,19 @@ class ConfigManager {
624624
// Definite assignment assertion - property will be assigned in initialize()
625625
apiUrl!: string;
626626
timeout!: number;
627-
debug?: boolean; // Optional property for comparison
628-
627+
debug?: boolean; // Optional property for comparison
628+
629629
// Additional properties with assertions
630630
initialized!: boolean;
631631
settings!: { [key: string]: any };
632-
632+
633633
initialize(url: string, timeoutMs: number) {
634634
this.apiUrl = url;
635635
this.timeout = timeoutMs;
636636
this.initialized = true;
637637
this.settings = { theme: "dark" };
638638
}
639-
639+
640640
isReady(): boolean {
641641
return this.initialized;
642642
}
@@ -673,6 +673,94 @@ auto ConfigManager::initialize(js::string url, js::number timeoutMs) {
673673
674674
**Note:** The definite assignment assertion (`!`) is a TypeScript compile-time feature that suppresses strict property initialization checking. In C++, this translates to declaring properties without initializers, which is the natural behavior. TypeScript2Cxx handles this automatically - properties with definite assignment assertions are transpiled as regular C++ member variables that are assigned later in constructors or initialization methods.
675675
676+
#### Const Type Parameters Support
677+
678+
TypeScript 5.0+ introduces const type parameters using the `const` modifier on generic type parameters. This feature enables better type inference and literal type preservation in generic functions and classes.
679+
680+
**TypeScript Example:**
681+
682+
```typescript
683+
// Basic const type parameter
684+
function identity<const T>(value: T): T {
685+
return value;
686+
}
687+
688+
// Multiple const type parameters
689+
function pair<const T, const U>(first: T, second: U): [T, U] {
690+
return [first, second];
691+
}
692+
693+
// Mixed const and non-const parameters
694+
function mixed<const T, U>(constParam: T, normalParam: U): void {
695+
console.log("Const:", constParam, "Normal:", normalParam);
696+
}
697+
698+
// Const type parameter on class method
699+
class Container {
700+
store<const T>(value: T): T {
701+
return value;
702+
}
703+
}
704+
705+
// Generic class with const type parameter
706+
class TypedContainer<const T> {
707+
private value: T;
708+
709+
constructor(initialValue: T) {
710+
this.value = initialValue;
711+
}
712+
713+
getValue(): T {
714+
return this.value;
715+
}
716+
}
717+
```
718+
719+
**Generated C++ Code:**
720+
721+
```cpp
722+
// Function templates with const comments
723+
template</* const */ typename T>
724+
T identity(T value) {
725+
return value;
726+
}
727+
728+
template</* const */ typename T, /* const */ typename U>
729+
js::any pair(T first, U second) {
730+
return js::array<js::any>{first, second};
731+
}
732+
733+
template</* const */ typename T, typename U>
734+
void mixed(T constParam, U normalParam) {
735+
js::console.log("Const:"_S, constParam, "Normal:"_S, normalParam);
736+
}
737+
738+
// Class with const type parameter method
739+
class Container {
740+
public:
741+
template</* const */ typename T>
742+
T store(T value) {
743+
return value;
744+
}
745+
};
746+
747+
// Generic class with const type parameter
748+
template</* const */ typename T>
749+
class TypedContainer {
750+
private:
751+
T value;
752+
753+
public:
754+
TypedContainer(T initialValue) : value(initialValue) {}
755+
756+
T getValue() {
757+
return value;
758+
}
759+
};
760+
```
761+
762+
**Note:** Const type parameters are a TypeScript compile-time feature for improved type inference and literal type preservation. In C++, TypeScript2Cxx generates standard template parameters but adds `/* const */` comments to indicate which parameters had the const modifier in the original TypeScript code. This helps maintain readability and provides context for developers familiar with the TypeScript source.
763+
676764
### 🔧 Implementation Details
677765
678766
- **Type System**:
@@ -694,8 +782,11 @@ auto ConfigManager::initialize(js::string url, js::number timeoutMs) {
694782
- **Transform Layer**:
695783
- Enhanced type assertion (`as`) expression handling to properly pass through expressions
696784
- Type aliases now correctly skip runtime code generation (they're compile-time only)
785+
- Added `hasConstModifier` method for detecting const modifiers on type parameters
786+
- Enhanced `IRTemplateParameter` interface with `isConst` flag for const type parameter tracking
697787
- **Code Generation**:
698788
- Fixed Object identifier mapping (was incorrectly dual-mapped to both js::Object and js::object)
789+
- Enhanced template parameter generation to include `/* const */` comments for const type parameters
699790
- **Runtime Library**:
700791
- Added `js::Object` namespace with static utility methods
701792

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ Based on analysis of both reference implementations:
245245
- [x] Satisfies operator (v0.8.6-dev)
246246
- [x] Non-null assertion operator (!) (v0.8.6-dev)
247247
- [x] Definite assignment assertion (!) (v0.8.6-dev)
248-
- Const type parameters
248+
- [x] Const type parameters (v0.8.6-dev)
249249
- NoInfer utility type
250250
- TypedArray support
251251
- Tuple types with rest elements

src/codegen/generator.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,8 @@ class CppGenerator {
432432
if (func.templateParams && func.templateParams.length > 0) {
433433
const templateParams = func.templateParams.map((tp) => {
434434
const constraint = tp.constraint || "typename";
435-
return `${constraint} ${tp.name}`;
435+
const constComment = tp.isConst ? "/* const */ " : "";
436+
return `${constComment}${constraint} ${tp.name}`;
436437
}).join(", ");
437438
templateDecl += `template<${templateParams}>\n`;
438439
}
@@ -560,7 +561,8 @@ class CppGenerator {
560561
if (cls.templateParams && cls.templateParams.length > 0) {
561562
const templateParams = cls.templateParams.map((tp) => {
562563
const constraint = tp.constraint || "typename";
563-
return `${constraint} ${tp.name}`;
564+
const constComment = tp.isConst ? "/* const */ " : "";
565+
return `${constComment}${constraint} ${tp.name}`;
564566
}).join(", ");
565567
lines.push(`template<${templateParams}>`);
566568
}

src/ir/nodes.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,12 @@ export interface IRTemplateParameter {
415415

416416
/** Default type */
417417
defaultType?: string;
418+
419+
/** Is variadic */
420+
isVariadic: boolean;
421+
422+
/** Is const type parameter */
423+
isConst?: boolean;
418424
}
419425

420426
/**
@@ -486,23 +492,6 @@ export interface IRParameter {
486492
decorators?: IRDecorator[];
487493
}
488494

489-
/**
490-
* Template parameter
491-
*/
492-
export interface IRTemplateParameter {
493-
/** Parameter name */
494-
name: string;
495-
496-
/** Constraint (e.g., "typename", "class", or concept) */
497-
constraint?: string;
498-
499-
/** Default type */
500-
defaultType?: string;
501-
502-
/** Is variadic */
503-
isVariadic: boolean;
504-
}
505-
506495
/**
507496
* Class declaration
508497
*/

src/transform/transformer.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,11 +2665,41 @@ class ASTTransformer {
26652665
defaultType = this.resolveType(node.default);
26662666
}
26672667

2668+
// Check for const modifier (TypeScript 5.0+ feature)
2669+
const isConst = this.hasConstModifier(node);
2670+
26682671
return {
26692672
name,
26702673
constraint,
26712674
defaultType,
26722675
isVariadic: false, // TypeScript doesn't have variadic type parameters like C++
2676+
isConst,
26732677
};
26742678
}
2679+
2680+
/**
2681+
* Check if a type parameter has the const modifier
2682+
*/
2683+
private hasConstModifier(node: ts.TypeParameterDeclaration): boolean {
2684+
// Check for const modifier on type parameters
2685+
// TypeScript 5.0+ stores const modifier differently
2686+
const anyNode = node as any;
2687+
2688+
// Try different ways to access const modifier
2689+
if (anyNode.modifiers) {
2690+
const modifiers = anyNode.modifiers as ts.NodeArray<ts.Modifier>;
2691+
if (modifiers.some((m) => m.kind === ts.SyntaxKind.ConstKeyword)) {
2692+
return true;
2693+
}
2694+
}
2695+
2696+
// Check if node has const property directly
2697+
if (anyNode.const === true) {
2698+
return true;
2699+
}
2700+
2701+
// Check standard modifiers API
2702+
const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
2703+
return modifiers ? modifiers.some((m) => m.kind === ts.SyntaxKind.ConstKeyword) : false;
2704+
}
26752705
}

0 commit comments

Comments
 (0)