@@ -30,6 +30,8 @@ import {
3030 isShorthandPropertyAssignment ,
3131 isEnumMember ,
3232 isClassLikeDeclaration ,
33+ isInterfaceDeclaration ,
34+ isSourceFile ,
3335} from '../typeguard/node' ;
3436
3537export function isEmptyObjectType ( type : ts . Type ) : type is ts . ObjectType {
@@ -205,6 +207,29 @@ export function getPropertyOfType(type: ts.Type, name: ts.__String) {
205207 return type . getProperties ( ) . find ( ( s ) => s . escapedName === name ) ;
206208}
207209
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+
208233/** Determines if writing to a certain property of a given type is allowed. */
209234export function isPropertyReadonlyInType ( type : ts . Type , name : ts . __String , checker : ts . TypeChecker ) : boolean {
210235 let seenProperty = false ;
@@ -285,11 +310,26 @@ export function getPropertyNameFromType(type: ts.Type): PropertyName | undefined
285310 }
286311 if ( isUniqueESSymbolType ( type ) )
287312 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+ } ]`,
289317 symbolName : type . escapedName ,
290318 } ;
291319}
292320
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+
293333export function getSymbolOfClassLikeDeclaration ( node : ts . ClassLikeDeclaration , checker : ts . TypeChecker ) {
294334 return checker . getSymbolAtLocation ( node . name ?? getChildOfKind ( node , ts . SyntaxKind . ClassKeyword ) ! ) ! ;
295335}
0 commit comments