Skip to content

Instantly share code, notes, and snippets.

@haxiomic
Last active February 26, 2023 11:44
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haxiomic/ad4f5d329ac616543819395f42037aa1 to your computer and use it in GitHub Desktop.
Save haxiomic/ad4f5d329ac616543819395f42037aa1 to your computer and use it in GitHub Desktop.
Haxe macro to make all fields of a type optional (similar to Typescript's Partial<T>)
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.TypeTools;
#if !macro
@:genericBuild(PartialMacro.build())
#end
class Partial<T> {}
class PartialMacro {
#if macro
@:access(haxe.macro.TypeTools)
static function build()
{
switch Context.getLocalType()
{
// Match when class's type parameter leads to an anonymous type (we convert to a complex type in the process to make it easier to work with)
case TInst(_, [Context.followWithAbstracts(_) => TypeTools.toComplexType(_) => TAnonymous(fields)]):
// Add @:optional meta to all fields
var newFields = fields.map(addMeta);
return TAnonymous(newFields);
// Match when type parameter leads to a class instance
case TInst(_, [Context.followWithAbstracts(_) => TInst(_.get() => _.fields.get() => classFields, params)]):
// Convert all fields to anon fields and then add @:optional to each
var anonFields: Array<Field> = classFields.map(TypeTools.toField);
var newFields = anonFields.map(addMeta);
return TAnonymous(newFields);
default:
Context.fatalError('Type parameter should be an anonymous structure', Context.currentPos());
}
return null;
}
static function addMeta(field: Field): Field
{
// Handle Null<T> and optional fields already parsed by the compiler
var kind = switch (field.kind) {
case FVar(TPath({
name: 'StdTypes',
sub: 'Null',
params: [TPType(TPath(tpath))]
}), write):
FVar(TPath(tpath), write);
default:
field.kind;
}
return {
name: field.name,
kind: kind,
access: field.access,
meta: field.meta.concat([{
name: ':optional',
params: [],
pos: Context.currentPos()
}]),
pos: field.pos
};
}
#end
}
@anissen
Copy link

anissen commented Jan 17, 2017

Here's an example usage: http://try-haxe.mrcdk.com/#0B57b

@haxiomic
Copy link
Author

Thanks @anissen, I didn't know there was a try-haxe version that supports macros!

@al-arz
Copy link

al-arz commented Jan 24, 2017

Mind adding this to code cookbook?

@fullofcaffeine
Copy link

Very nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment