@@ -30,6 +30,8 @@ import {
30
30
isShorthandPropertyAssignment ,
31
31
isEnumMember ,
32
32
isClassLikeDeclaration ,
33
+ isInterfaceDeclaration ,
34
+ isSourceFile ,
33
35
} from '../typeguard/node' ;
34
36
35
37
export function isEmptyObjectType ( type : ts . Type ) : type is ts . ObjectType {
@@ -205,6 +207,29 @@ export function getPropertyOfType(type: ts.Type, name: ts.__String) {
205
207
return type . getProperties ( ) . find ( ( s ) => s . escapedName === name ) ;
206
208
}
207
209
210
+ export function getWellKnownSymbolPropertyOfType ( type : ts . Type , wellKnownSymbolName : string , checker : ts . TypeChecker ) {
211
+ const prefix = '__@' + wellKnownSymbolName ;
212
+ for ( const prop of type . getProperties ( ) ) {
213
+ if ( ! prop . name . startsWith ( prefix ) )
214
+ continue ;
215
+ const globalSymbol = checker . getApparentType (
216
+ checker . getTypeAtLocation ( ( < ts . ComputedPropertyName > ( < ts . NamedDeclaration > prop . valueDeclaration ) . name ) . expression ) ,
217
+ ) . symbol ;
218
+ if ( prop . escapedName === getPropertyNameOfWellKnownSymbol ( checker , globalSymbol , wellKnownSymbolName ) )
219
+ return prop ;
220
+ }
221
+ return ;
222
+ }
223
+
224
+ function getPropertyNameOfWellKnownSymbol ( checker : ts . TypeChecker , symbolConstructor : ts . Symbol | undefined , symbolName : string ) {
225
+ const knownSymbol = symbolConstructor &&
226
+ checker . getTypeOfSymbolAtLocation ( symbolConstructor , symbolConstructor . valueDeclaration ) . getProperty ( symbolName ) ;
227
+ const knownSymbolType = knownSymbol && checker . getTypeOfSymbolAtLocation ( knownSymbol , knownSymbol . valueDeclaration ) ;
228
+ if ( knownSymbolType && isUniqueESSymbolType ( knownSymbolType ) )
229
+ return knownSymbolType . escapedName ;
230
+ return < ts . __String > ( '__@' + symbolName ) ;
231
+ }
232
+
208
233
/** Determines if writing to a certain property of a given type is allowed. */
209
234
export function isPropertyReadonlyInType ( type : ts . Type , name : ts . __String , checker : ts . TypeChecker ) : boolean {
210
235
let seenProperty = false ;
@@ -285,11 +310,26 @@ export function getPropertyNameFromType(type: ts.Type): PropertyName | undefined
285
310
}
286
311
if ( isUniqueESSymbolType ( type ) )
287
312
return {
288
- displayName : `[${ type . symbol ? type . symbol . name : ( < string > type . escapedName ) . replace ( / ^ _ _ @ | @ \d + $ / g, '' ) } ]` ,
313
+ displayName : `[${ type . symbol
314
+ ? `${ isKnownSymbol ( type . symbol ) ? 'Symbol.' : '' } ${ type . symbol . name } `
315
+ : ( < string > type . escapedName ) . replace ( / ^ _ _ @ | @ \d + $ / g, '' )
316
+ } ]`,
289
317
symbolName : type . escapedName ,
290
318
} ;
291
319
}
292
320
321
+ function isKnownSymbol ( symbol : ts . Symbol ) : boolean {
322
+ return isSymbolFlagSet ( symbol , ts . SymbolFlags . Property ) &&
323
+ symbol . valueDeclaration !== undefined &&
324
+ isInterfaceDeclaration ( symbol . valueDeclaration . parent ) &&
325
+ symbol . valueDeclaration . parent . name . text === 'SymbolConstructor' &&
326
+ isGlobalDeclaration ( symbol . valueDeclaration . parent ) ;
327
+ }
328
+
329
+ function isGlobalDeclaration ( node : ts . DeclarationStatement ) : boolean {
330
+ return isNodeFlagSet ( node . parent ! , ts . NodeFlags . GlobalAugmentation ) || isSourceFile ( node . parent ) && ! ts . isExternalModule ( node . parent ) ;
331
+ }
332
+
293
333
export function getSymbolOfClassLikeDeclaration ( node : ts . ClassLikeDeclaration , checker : ts . TypeChecker ) {
294
334
return checker . getSymbolAtLocation ( node . name ?? getChildOfKind ( node , ts . SyntaxKind . ClassKeyword ) ! ) ! ;
295
335
}
0 commit comments