Description
Specification
It would be nice for users to be able to extend IdInternal
which can allow us to specialise the encoding functions into the child classes.
class NodeIdInternal extends IdInternal {
pubic toMultibase(): string {
return super.toMultibase('base32hex');
}
}
const nodeId = NodeIdInternal.create(/* ... */);
nodeId.toMultibase();
// instead of nodesUtils.encodeNodeId();
However this is not really possible easily due to the fact that Id
type is a union of IdInternal
and number
.
There's a potential way to do this though with "polymorphic static this" MatrixAI/Polykey#321 (comment)
type Id<T = IdInternal> = T & number;
class IdInternal extends Uint8Array {
static create<T extends typeof IdInternal>(this: T): Id<InstanceType<T>> {
return (new this() as Id<InstanceType<T>>);
}
baseMethod () {
}
}
type NodeId = Id<NodeIdInternal>;
class NodeIdInternal extends IdInternal {
derivedMethod () { }
}
class ClaimIdInternal extends IdInternal {
anotherMethod () {}
}
class SomeOtherIdOfId extends ClaimIdInternal {
}
const x = IdInternal.create();
const y = NodeIdInternal.create();
const z = SomeOtherIdOfId.create();
// console.log(x.baseMethod());
function doSomething(x: NodeId) {
const pojo = { };
pojo[x] = 123;
}
doSomething(x); // this is a type error
doSomething(y);
This makes Id
itself a generic type, and it allows all downstream classes to override instance encoding methods like toMultibase
or otherwise, and also mean that NodeIdInternal.create
would create Id<NodeIdInternal>
, which you can match with type NodeId = Id<NodeIdInternal>
.
One tradeoff is that's complex for child classes to extend any static methods of IdInternal
, but that's unlikely to be needed at all. The only methods that child classes may want to extend are all the encoding methods, and potentially adding new features to their ID objects.
Note that this means right now where alot of functions hand off their decoding to idUtils
, they would need to be changed to refer to the current constructor. So like fromBuffer
cannot just call idUtils.fromBuffer
since that's hardcoded to call IdInternal
, but instead refer to this
.
Additional context
- General Data Validation - Boundary IO locations should be doing data validation and marshalling (and the decommissioning of GenericIdTypes for all IDs) Polykey#321 (comment) - discussion came up due to some verbosity of using utilities to encode and decode the node ids
- Polymorphic "this" for static members microsoft/TypeScript#5863 - discussion about polymorphic this
Tasks
- ...
- ...
- ...