@@ -66,7 +66,8 @@ export default (prior: ts.CompletionInfo): ts.CompletionEntry[] | void => {
66
66
const insertSnippetVariant = completingStyleMap . find ( ( [ , detector ] ) => detector ( type ! , typeChecker ) ) ?. [ 0 ] ?? fallbackSnippet
67
67
if ( ! insertSnippetVariant ) continue
68
68
const [ insertSnippetText , insertSnippetPreview ] = typeof insertSnippetVariant === 'function' ? insertSnippetVariant ( ) : insertSnippetVariant
69
- const insertText = insertTextAfterEntry ( entry , insertSnippetText )
69
+ let insertText = insertTextAfterEntry ( entry , insertSnippetText )
70
+ if ( node . getSourceFile ( ) . getFullText ( ) [ position ] === ',' ) insertText = insertText . slice ( 0 , - 1 )
70
71
const index = entries . indexOf ( entry )
71
72
entries . splice ( index + ( keepOriginal === 'before' ? 1 : 0 ) , keepOriginal === 'remove' ? 1 : 0 , {
72
73
...entry ,
@@ -100,10 +101,20 @@ const isEverySubtype = (type: ts.UnionType, predicate: (type: ts.Type) => boolea
100
101
} )
101
102
}
102
103
103
- const isStringCompletion = ( type : ts . Type ) => {
104
+ const isStringCompletion = ( type : ts . Type , checker : ts . TypeChecker ) => {
104
105
if ( type . flags & ts . TypeFlags . Undefined ) return false
105
106
if ( type . flags & ts . TypeFlags . StringLike ) return true
106
- if ( type . isUnion ( ) ) return isEverySubtype ( type , type => isStringCompletion ( type ) )
107
+ if ( type . isUnion ( ) )
108
+ return isEverySubtype (
109
+ type ,
110
+ type =>
111
+ isStringCompletion ( type , checker ) ||
112
+ // string & {} for string complete
113
+ ( type . isIntersection ( ) &&
114
+ type . types . length === 2 &&
115
+ type . types [ 0 ] ! . flags & ts . TypeFlags . String &&
116
+ checker [ 'isEmptyAnonymousObjectType' ] ( type . types [ 1 ] ) ) ,
117
+ )
107
118
return false
108
119
}
109
120
0 commit comments