@@ -101,7 +101,7 @@ auto TypeScript::operator()(const IRObject &entry) -> void {
101101 std::holds_alternative<bool >(entry.additional ) &&
102102 std::get<bool >(entry.additional )};
103103
104- if (has_typed_additional && entry.members .empty ()) {
104+ if (has_typed_additional && entry.members .empty () && entry. pattern . empty () ) {
105105 const auto &additional_type{std::get<IRType>(entry.additional )};
106106 this ->output << " export type " << type_name << " = Record<string, "
107107 << mangle (this ->prefix , additional_type.pointer ,
@@ -110,7 +110,7 @@ auto TypeScript::operator()(const IRObject &entry) -> void {
110110 return ;
111111 }
112112
113- if (allows_any_additional && entry.members .empty ()) {
113+ if (allows_any_additional && entry.members .empty () && entry. pattern . empty () ) {
114114 this ->output << " export type " << type_name
115115 << " = Record<string, unknown>;\n " ;
116116 return ;
@@ -136,6 +136,30 @@ auto TypeScript::operator()(const IRObject &entry) -> void {
136136 << " ;\n " ;
137137 }
138138
139+ for (const auto &pattern_property : entry.pattern ) {
140+ this ->output << " [key: `" << pattern_property.prefix << " ${string}`]: "
141+ << mangle (this ->prefix , pattern_property.pointer ,
142+ pattern_property.symbol , this ->cache );
143+
144+ // TypeScript requires that a more specific index signature type is
145+ // assignable to any less specific one that overlaps it. When a prefix
146+ // is a sub-prefix of another (i.e. "x-data-" starts with "x-"),
147+ // intersect the types so the constraint is satisfied
148+ for (const auto &other : entry.pattern ) {
149+ if (&other == &pattern_property) {
150+ continue ;
151+ }
152+
153+ if (pattern_property.prefix .starts_with (other.prefix )) {
154+ this ->output << " & "
155+ << mangle (this ->prefix , other.pointer , other.symbol ,
156+ this ->cache );
157+ }
158+ }
159+
160+ this ->output << " ;\n " ;
161+ }
162+
139163 if (allows_any_additional) {
140164 this ->output << " [key: string]: unknown | undefined;\n " ;
141165 } else if (has_typed_additional) {
@@ -155,6 +179,13 @@ auto TypeScript::operator()(const IRObject &entry) -> void {
155179 << " |\n " ;
156180 }
157181
182+ for (const auto &pattern_property : entry.pattern ) {
183+ this ->output << " "
184+ << mangle (this ->prefix , pattern_property.pointer ,
185+ pattern_property.symbol , this ->cache )
186+ << " |\n " ;
187+ }
188+
158189 const auto &additional_type{std::get<IRType>(entry.additional )};
159190 this ->output << " "
160191 << mangle (this ->prefix , additional_type.pointer ,
0 commit comments