If you control both definition of TNode, you could do it like this (Does not need to be in same unit, but must reference the same constant) :
const
NODE_IS_RECORD = False;
type
{$if NODE_IS_RECORD}
TNode = record
end;
PNode = ^TNode;
{$ELSE}
TNode = class
end;
PNode = TNode;
{$IFEND}
If you control only 1 declaration of TNode, you could still do it like this :
{Unit1}
type
TNode = record
end;
PNode = ^TNode;
{Unit2}
{$IF not DECLARED(PNode)}
//if you don't use the unit where TNode is a record, then PNode shouldn't be declared.
PNode = TNode;
{$ENDIF}
If you control neither declaration, but they are declared in different units(Actually, I think it's required...) and you never use both, or using both always means you want to use a specific declaration of PNode :
{$IF DECLARED(UnitContainingTNodeAsRecord)}
PNode = ^TNode;
{$ELSE}
PNode = TNode;
{$IFEND}
You might want to prefix TNode with the name of the unit if you have both unit in the uses. "DECLARED" only ensure it is declared, not that it's the "closest" in scope.
I think that covers most situations.