typelite


Typelite: Why is Dictionary<string, object> mapped to KeyValuePair and not to any or [index:string]:any


I have a class,
public class Instance : IResource
{
public Dictionary<string, object> Value { get; set; }
and it is mapped to
interface Instance {
Value: System.Collections.Generic.KeyValuePair[];
interface KeyValuePair {
Key: any;
Value: any;
}
I would have expected
interface Instance {
Value: any;
or
interface Instance {
Value: {[index:string]:any};
How can I change the generation?
Also, how can I skip the name space in the generation?
A quick and dirty workaround is to use a regex to alter output:
Using
<#= Regex.Replace( ts.Generate(TsGeneratorOutput.Properties)
, #":\s*System\.Collections\.Generic\.KeyValuePair\<(?<k>[^\,]+),(?<v>[^\,]+)\>\[\];"
, m=>": {[key: "+m.Groups["k"].Value+"]: "+m.Groups["v"].Value+"};"
, RegexOptions.Multiline)
#>
Transforms a field
myField: System.Collections.Generic.KeyValuePair<string,OtherClass>[];
to
myField: {[key: string]: OtherClass};
Collection types (any type implementing IEnumerable) is converted to arrays. Dictionary<> implements IEnumerable<KeyValuePair<>> and thus is converted to an array. The item-type is then expanded to its fully qualified name (FQN): System.Collections.Generic.KeyValuePair.
Using Type Converters will let you change the type-name, but not the FQN. So it is only applicable to local types. In the case of dictionaries, you can't change the item type by inheritance.
You could either create a new dictionary type, without inheriting from Dictionary<>. Another way around this problem, is to also use Type Formatters:
ts.WithConvertor<Dictionary<string,object>>(t => {
// Embed the real type in $
// "System.Collections.Generic.${ [key: string]: any }$[]"
return "${ [key: string]: any }$";
});
ts.WithFormatter((string memberTypeName, bool isMemberCollection) => {
// Extract the content inside $
string[] pieces = memberTypeName.Split('$');
if (pieces.Length == 3) return pieces[1];
// Default behaviour
return memberTypeName + (isMemberCollection ? "[]" : "");
});
Here's a more generalized (and updated) solution that builds off of Markus Jarderot's answer:
static void RegisterDictionaryMemberFormatter(this TsGenerator tsGenerator)
{
tsGenerator.SetMemberTypeFormatter((tsProperty, memberTypeName) => {
var dictionaryInterface =
tsProperty.PropertyType.Type.GetInterface(typeof(IDictionary<,>).Name) ??
tsProperty.PropertyType.Type.GetInterface(typeof(IDictionary).Name);
if (dictionaryInterface != null)
{
return tsGenerator.GetFullyQualifiedTypeName(new TsClass(dictionaryInterface));
}
else
{
return tsGenerator.DefaultMemberTypeFormatter(tsProperty, memberTypeName);
}
});
}
// and if you like the fluent syntax...
static TypeScriptFluent WithDictionaryMemberFormatter(this TypeScriptFluent typeScriptFluent)
{
typeScriptFluent.ScriptGenerator.RegisterDictionaryMemberFormatter();
return typeScriptFluent;
}
Use it like this:
var ts = TypeLite.TypeScript.Definitions().For(typeof(SomeClass).Assembly);
ts.ScriptGenerator.RegisterDictionaryMemberFormatter();
// alternatively with fluent syntax:
var ts = TypeLite.TypeScript.Definitions()
.For(typeof(SomeClass).Assembly)
.WithDictionaryMemberFormatter();
N.B. this only fixes type signatures of properties (or fields) that have dictionary types. Also definitions for IDictionary are not automatically emitted, you'd have to add them manually:
declare module System.Collections.Generic {
interface IDictionary<TKey extends String, TValue> {
[key: string]: TValue;
}
}
declare module System.Collections {
interface IDictionary {
[key: string]: any;
}
}

Related Links

Typelite “Cannot load file or assembly” Autofac
TypeLite fresh install doesn't work
How to change TypeLite Output Directory
How to setup TypeLite to build types in other projects
Variant type and non, with same name
Ignoring types with fluent configuration in Typelite
IMemberIdentifier missing from TypeLite.TsModels namespace
Typelite Converts All Classes
Fluent module name change
TypeLite generate external modules?
Typelite: Why is Dictionary<string, object> mapped to KeyValuePair and not to any or [index:string]:any

Categories

HOME
macos-sierra
cucumber
focus
yahoo-weather-api
dotnetnuke
seedstack
braintree
portable-class-library
biztalk-2010
elk-stack
angular-meteor
stack-overflow
heuristics
sslhandshakeexception
squirrel-sql
mailgun
django-rq
google-tasks-api
mixpanel
tfsbuild
deepfreeze
clr
jest
error-logging
tableview
maven-surefire-plugin
ava
exchange-server-2010
animated-gif
cellular-network
python-appium
strophe.js
background-color
openbravo
boolean-logic
substance
netbios
publishing
nsmutablearray
kendo-listview
restful-architecture
autoencoder
cups
cargo
identify
resampling
oauth2-playground
fiware-wirecloud
type-inference
nomad
audio-converter
absolute
rm
uiautomatorviewer
sonicmq
entropy
exc-bad-access
front-camera
okio
visual-studio-monaco
traversable
wolfram-language
perforce-integrate
right-to-left
node.js-connect
ajaxmin
apache-pig-grunt
frame-grab
mnesia
deeplink
helm
python-cffi
in-app-billing
html.actionlink
apache-commons-digester
netdatacontractserializer
hmisc
domino-designer-eclipse
scala-macros
prism-4
shell-extensions
rubber
flurry-analytics
iodocs
image-rotation
category-theory
.htpasswd
commenting
facebook-game-groups
illuminate-container
boinc
mousemotionlistener
disjoint-union
libxml-js
tnt4j
jquery-cycle
oembed
cmath
ntlmv2
websphere-6.1
monocross
hardcode
mkannotation
dynamic-c
play2-mini
upshot
photo-management
django-pagination
multiple-users
android-input-method
yahoo-maps
acceleration
activex-exe
webclient.uploaddata
synthesizer

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App