Skip to content

Commit 46062a7

Browse files
authored
feat(api): Add support for types implementing raw IDictionary
Types that implement `IDictionary<,>` will now be rendered the same way as `Dictionary<,>`.
2 parents 09b9a3a + 7f4fc5d commit 46062a7

File tree

5 files changed

+65
-2
lines changed

5 files changed

+65
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare namespace Api {
2+
interface TypeWithCustomDictionaryProp {
3+
dictProp: { [key: string]: number };
4+
}
5+
}
6+
7+
---

src/Typescript.Tests/DictionaryTypes/DictionaryGeneratorTests.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@ public void Generator_TypeWithComplexDictionaryValueType_ShouldRenderToTypescrip
4040
this.Assent(generated.Types);
4141
}
4242

43+
class TypeWithCustomDictionaryProp
44+
{
45+
public ICustomDictionary DictProp { get; set; }
46+
}
47+
48+
interface ICustomDictionary : IDictionary<string, int>
49+
{
50+
}
51+
52+
[Fact]
53+
public void Generator_TypeWithCustomDictionaryValueType_ShouldRenderToTypescriptMap()
54+
{
55+
var generator = TypeScriptGenerator.CreateDefault();
56+
var generated = generator.Generate(new[] {typeof(TypeWithCustomDictionaryProp)});
57+
58+
this.Assent(generated.JoinTypesAndEnums());
59+
}
60+
4361
enum TestEnum
4462
{
4563
FirstValue,
@@ -60,6 +78,5 @@ public void Generator_TypeWithEnumValueType_ShouldRenderToTypescriptMap()
6078

6179
this.Assent(generated.JoinTypesAndEnums());
6280
}
63-
6481
}
6582
}

src/Typescriptr/Traverse.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace Typescriptr
5+
{
6+
internal static class Traverse
7+
{
8+
public static IEnumerable<T> Across<T>(T first, Func<T, T> next) where T : class
9+
{
10+
for (var item = first; item != null; item = next(item))
11+
yield return item;
12+
}
13+
}
14+
}

src/Typescriptr/TypeExtensions.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
6+
namespace Typescriptr
7+
{
8+
internal static class TypeExtensions
9+
{
10+
public static bool IsClosedTypeOf(this Type @this, Type openGeneric)
11+
{
12+
return TypesAssignableFrom(@this).Any(t =>
13+
{
14+
if (!t.GetTypeInfo().IsGenericType || @this.GetTypeInfo().ContainsGenericParameters) return false;
15+
return t.GetGenericTypeDefinition() == openGeneric;
16+
});
17+
}
18+
19+
private static IEnumerable<Type> TypesAssignableFrom(Type candidateType)
20+
{
21+
return candidateType.GetTypeInfo().ImplementedInterfaces
22+
.Concat(Traverse.Across(candidateType, t => t.GetTypeInfo().BaseType));
23+
}
24+
}
25+
}

src/Typescriptr/TypeScriptGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ private string TypeNameRenderer(Type type)
253253
if (_propTypeMap.ContainsKey(type))
254254
return decorate(_propTypeMap[type]);
255255

256-
if (typeof(IDictionary).IsAssignableFrom(type))
256+
if (type.IsClosedTypeOf(typeof(IDictionary<,>)))
257257
return decorate(_dictionaryPropertyFormatter(type, TypeNameRenderer));
258258

259259
if (typeof(IEnumerable).IsAssignableFrom(type))

0 commit comments

Comments
 (0)