Typelite: how to set nullable C# types to nullable Typescript types with T4 transform?
Asked Answered
T

4

5

I'm using Typelite 9.5.0 to convert my C# classes to Typescript interfaces. I want that a nullable type in (e.g. Guid?) is converted to a nullable type in Typescript.

Currently I have this C# class:

public class PersistentClassesReferences
{
public Guid? EmailMessageId { get; set; }
public Guid? FileMetaDataId { get; set; }
public Guid? IssueId { get; set; }
public Guid? ProjectId { get; set; }
}

But that is converted with Typelite to this Typescript interface:

interface IPersistentClassesReferences {
    EmailMessageId : System.IGuid;
    FileMetaDataId : System.IGuid;
    IssueId : System.IGuid;
    ProjectId : System.IGuid;
}

But when I want to create a new typescript variable from this interface, the compiler complains when I don't have all the properties set (null of some value).

Therefore I had a template in place that test for nullable type, and if so adds an ?

var isNullabe = Nullable.GetUnderlyingType(tsprop.ClrProperty.PropertyType) != null;
if (isNullabe)
{
    return identifier.Name + "? ";
}

This did work, but not anymore (I think after the upgrade to Typelite 9.5.0 or some other nugetpackage update).

I get the error message:

 Compiling transformation: 'System.Reflection.MemberInfo' does not contain a
 definition for 'PropertyType' and no extension method 'PropertyType' accepting
 a first argument of type 'System.Reflection.MemberInfo' could be found (are you
 missing a using directive or an assembly reference?)           

How can I add a question mark to the identifiername?

Treatise answered 26/9, 2014 at 6:37 Comment(0)
E
3

If you want to use a TypeLite formatter this should work:

var propertyInfo = tsprop.ClrProperty as PropertyInfo;
var propertyType = propertyInfo != null ? propertyInfo.PropertyType : ((FieldInfo)tsprop.ClrProperty).FieldType;    
var isNullabe = Nullable.GetUnderlyingType(propertyType) != null;
if (isNullabe) {
    return identifier.Name + "? ";
}
Epicanthus answered 26/9, 2014 at 21:9 Comment(0)
R
10

You can create it with the TsProperty Attribute, for example the following C# code will result in an optional property:

[TsClass]
public class Person
{
    [TsProperty(IsOptional=true)]
    public string Name { get; set; }
    public List<Address> Addresses { get; set; }
}

This will generate the following TypeScript definition

interface Person {
    Name?: string;
    Addresses: TypeScriptHTMLApp1.Address[];
}

You can find more about this here: docs

See the code where it does it here: code

Reflex answered 26/9, 2014 at 9:52 Comment(0)
E
3

If you want to use a TypeLite formatter this should work:

var propertyInfo = tsprop.ClrProperty as PropertyInfo;
var propertyType = propertyInfo != null ? propertyInfo.PropertyType : ((FieldInfo)tsprop.ClrProperty).FieldType;    
var isNullabe = Nullable.GetUnderlyingType(propertyType) != null;
if (isNullabe) {
    return identifier.Name + "? ";
}
Epicanthus answered 26/9, 2014 at 21:9 Comment(0)
G
3

In response to Lukas' answer:

Anyone reading this and using a later version of TypeLite will find that TsProperty no longer has a property called ClrProperty. It's now called MemberInfo (and is of type MemberInfo).

Here is an example of a MemberFormatter that turns nullable C# types into optional TypeScript properties. It also makes members camel case named:

.WithMemberFormatter((identifier) => {
    var tsprop = identifier as TsProperty;

    if (tsprop != null)
    {
        var clrProperty = tsprop.MemberInfo as PropertyInfo;
        var isNullabe = Nullable.GetUnderlyingType(clrProperty.PropertyType) != null;
        if (isNullabe)
        {
            return Char.ToLower(identifier.Name[0]) + identifier.Name.Substring(1) + "?";
        }
    }

    return Char.ToLower(identifier.Name[0]) + identifier.Name.Substring(1);
});
Goodale answered 13/5, 2016 at 19:51 Comment(0)
Z
0

The good news is that you don't need to do this as the ? modifier in TypeScript actually makes the entire member optional for the purposes of structural type comparison. As you only want to make the types nullable, you need to do anything as you can null any type in TypeScript already:

var a: number = null;
var b: boolean = null;
var c: string = null;
var d: string[] = null;
//... and so on

Here is a demo of how the ? works in TypeScript (it isn't to do with nullability):

interface Example {
    a?: string;
    b: string;
}

var both = { a: '', b: '' };
var onlyB = { b: '' };
var onlyA = { a: '' };

function doExample(x: Example) {
    return x;
}

// Fine
doExample(both);

// Fine
doExample(onlyB);

// Not fine - compiler warning
doExample(onlyA);

When the compiler checks the arguments passed to doExample, it will allow the a property to be omitted, because it has the ?. The b property must be supplied.

Zared answered 26/9, 2014 at 7:40 Comment(1)
That's true what you are saying, but I have a C# class that needs to be converted (by Typelite T4) to Typescript. In my case c# types that are nullable or not nullable in the interface it is converted to (but of course should be nullable). I've updated my post to reflect my question better.Treatise

© 2022 - 2024 — McMap. All rights reserved.