33
44import ts from "typescript" ;
55
6+ import { isSymbolLinkFlagSet } from "../flags" ;
67import {
78 isConstAssertionExpression ,
89 isEntityNameExpression ,
@@ -27,11 +28,24 @@ export function isBindableObjectDefinePropertyCall(
2728 ) ;
2829}
2930
31+ /**
32+ * Detects whether the property assignment is affected by an enclosing `as const` assertion or const type parameter and therefore treated literally.
33+ */
34+ export function isInConstContext (
35+ node : ts . PropertyAssignment | ts . ShorthandPropertyAssignment ,
36+ typeChecker : ts . TypeChecker ,
37+ ) : boolean {
38+ return (
39+ isInAsConstContext ( node . parent ) ||
40+ isInConstTypeParameterContext ( node , typeChecker )
41+ ) ;
42+ }
43+
3044/**
3145 * Detects whether an expression is affected by an enclosing `as const` assertion and therefore treated literally.
3246 * @internal
3347 */
34- export function isInConstContext ( node : ts . Expression ) : boolean {
48+ function isInAsConstContext ( node : ts . Expression ) : boolean {
3549 let current : ts . Node = node ;
3650 while ( true ) {
3751 const parent = current . parent ;
@@ -74,3 +88,42 @@ export function isInConstContext(node: ts.Expression): boolean {
7488 }
7589 }
7690}
91+
92+ /**
93+ * Detects whether a property assignment is affected by a const type parameter and therefore treated literally.
94+ * @internal
95+ */
96+ function isInConstTypeParameterContext (
97+ node : ts . PropertyAssignment | ts . ShorthandPropertyAssignment ,
98+ typeChecker : ts . TypeChecker ,
99+ ) : boolean {
100+ let current : ts . PropertyAssignment | ts . ShorthandPropertyAssignment = node ;
101+ let callExpression : ts . CallExpression ;
102+
103+ while ( true ) {
104+ if (
105+ ts . isPropertyAssignment ( current . parent . parent ) ||
106+ ts . isShorthandPropertyAssignment ( current . parent . parent )
107+ ) {
108+ current = current . parent . parent ;
109+ continue ;
110+ }
111+
112+ if ( ts . isCallExpression ( current . parent . parent ) ) {
113+ callExpression = current . parent . parent ;
114+ break ;
115+ }
116+
117+ return false ;
118+ }
119+
120+ const type = typeChecker . getTypeAtLocation ( callExpression ) ;
121+ const property = type
122+ . getProperties ( )
123+ . find ( ( property ) => property . getName ( ) === current . name . getText ( ) ) ;
124+
125+ return (
126+ property !== undefined &&
127+ isSymbolLinkFlagSet ( property , ts . ModifierFlags . Readonly )
128+ ) ;
129+ }
0 commit comments