Skip to content

Commit a3f96e3

Browse files
authored
feat(api): Add support for generics
Add support for generics - thanks to @lavinski
2 parents b0eec50 + 5f05e3f commit a3f96e3

6 files changed

+144
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare namespace Api {
2+
interface TypeWithGenericArguments extends BaseType<Alpha, Beta> {
3+
}
4+
interface BaseType<T1, T2> {
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare namespace Api {
2+
interface TypeWithOpenGenericArguments<T> {
3+
}
4+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using Assent;
3+
using Typescriptr;
4+
using Typescriptr.Formatters;
5+
using Xunit;
6+
using Xunit.Abstractions;
7+
8+
namespace Typescript.Tests.Generics
9+
{
10+
public class GenericsGeneratorTests
11+
{
12+
class Alpha { }
13+
class Beta { }
14+
15+
class BaseType<T1, T2>
16+
{
17+
}
18+
19+
class TypeWithGenericArguments : BaseType<Alpha, Beta>
20+
{
21+
}
22+
23+
[Fact]
24+
public void Generator_TypeWithGenericArguments_GeneratesSuccessfully()
25+
{
26+
var generator = TypeScriptGenerator.CreateDefault();
27+
var generated = generator.Generate(new[] {typeof(TypeWithGenericArguments) });
28+
29+
var result = generated.Types;
30+
31+
this.Assent(result);
32+
}
33+
34+
class TypeWithOpenGenericArguments<T>
35+
{
36+
}
37+
38+
[Fact]
39+
public void Generator_TypeWithOpenGenericArguments_GeneratesSuccessfully()
40+
{
41+
var generator = TypeScriptGenerator.CreateDefault();
42+
var generated = generator.Generate(new[] { typeof(TypeWithOpenGenericArguments<>) });
43+
44+
var result = generated.Types;
45+
46+
this.Assent(result);
47+
}
48+
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare namespace Api {
2+
interface TypeWithBaseClass extends BaseClass {
3+
}
4+
interface BaseClass {
5+
property: string;
6+
}
7+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using Assent;
3+
using Typescriptr;
4+
using Typescriptr.Formatters;
5+
using Xunit;
6+
using Xunit.Abstractions;
7+
8+
namespace Typescript.Tests.Inheritence
9+
{
10+
public class InheritenceGeneratorTests
11+
{
12+
class BaseClass
13+
{
14+
public string Property { get; set; }
15+
}
16+
17+
class TypeWithBaseClass : BaseClass
18+
{
19+
20+
}
21+
22+
[Fact]
23+
public void Generator_TypeWithBaseClass_GeneratesSuccessfully()
24+
{
25+
var generator = TypeScriptGenerator.CreateDefault();
26+
var generated = generator.Generate(new[] {typeof(TypeWithBaseClass) });
27+
28+
this.Assent(generated.Types);
29+
}
30+
}
31+
}

src/Typescriptr/TypeScriptGenerator.cs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,24 @@ private void RenderType(StringBuilder builder, Type type)
172172
: MemberTypes.Property | MemberTypes.Field;
173173

174174
var members = type.GetMembers().Where(m => memberTypesToInclude.HasFlag(m.MemberType));
175-
builder.AppendLine($"interface {type.Name} {{");
175+
176+
bool ShouldExport(Type t)
177+
{
178+
return t != typeof(Object)
179+
&& t != typeof(ValueType)
180+
&& t != null;
181+
}
182+
var baseType = type.BaseType;
183+
var hasBaseType = ShouldExport(baseType);
184+
185+
builder.Append($"interface ");
186+
RenderTypeName(builder, type);
187+
if (hasBaseType) {
188+
builder.Append($" extends ");
189+
RenderTypeName(builder, baseType);
190+
}
191+
192+
builder.AppendLine(" {");
176193

177194
foreach (var memberInfo in members)
178195
{
@@ -187,16 +204,39 @@ private void RenderType(StringBuilder builder, Type type)
187204
if (_useCamelCasePropertyNames)
188205
memberName = memberName.ToCamelCase();
189206

190-
RenderProperty(builder, memberType, memberName);
207+
if (memberInfo.DeclaringType == type) {
208+
RenderProperty(builder, memberType, memberName);
209+
}
191210
}
192211

193212
builder.AppendLine("}");
194213
_typesGenerated.Add(type);
195214

196-
var baseType = type.BaseType;
197-
if (baseType != typeof(Object) && baseType != typeof(ValueType) && baseType != null)
198-
if (!_typesGenerated.Contains(baseType))
199-
_typeStack.Push(baseType);
215+
if (hasBaseType) {
216+
var addedType = baseType.IsGenericType ? baseType.GetGenericTypeDefinition() : baseType;
217+
if (!_typesGenerated.Contains(addedType))
218+
_typeStack.Push(addedType);
219+
}
220+
}
221+
222+
private void RenderTypeName(StringBuilder builder, Type type)
223+
{
224+
var friendlyName = type.Name;
225+
if (type.IsGenericType) {
226+
var backtickIndex = friendlyName.IndexOf('`');
227+
if (backtickIndex > 0) {
228+
builder.Append(friendlyName.Remove(backtickIndex));
229+
}
230+
builder.Append("<");
231+
var typeParameters = type.GetGenericArguments();
232+
for (var i = 0; i < typeParameters.Length; ++i) {
233+
if (i > 0) { builder.Append(", "); }
234+
RenderTypeName(builder, typeParameters[i]);
235+
}
236+
builder.Append(">");
237+
} else {
238+
builder.Append(friendlyName);
239+
}
200240
}
201241

202242
private string TypeNameRenderer(Type type)

0 commit comments

Comments
 (0)