Reputation: 7422
I want to extend Uint8Array
such with a class that constrains the type to a certain length. For example:
class Bytes32 extends ByteArray {
constructor() { super(32) }
length: 32 = 32
}
However, when I try to instantiate that class I get an error because the length
property on Uint8Array
only has a getter:
TypeError: Cannot set property length of [object Object] which has only a getter
If I don't do the assignment in the class declaration and instead only do length: 32
then I get a compiler error saying that length
is never assigned.
Is there any way I can tell TypeScript (either via assertion of via proof) that the length
property of this class will always be 32
and thus its type should be narrowed to 32
from number
?
I specifically want the compiler to know about the narrowing so I can have a function with a signature like:
function apple(data: ArrayLike<number> & { length: 32 })
Such a signature would enhance type checking in my project, without tightly coupling to any specific array of numbers container. The only requirement is that the thing they give me must (provably by the compiler) have exactly 32 elements.
Upvotes: 2
Views: 459
Reputation: 31803
As you simply wish to refine the type of the length
member, specifically from number
to 32
, and are only initializing it to satisfy type checking and thereby introducing a runtime error, we can resolve the issue by leveraging Declaration Merging.
Specifically we can refine the typeof of length
to 32
by introducing an interface which declares the property and merges with the class itself.
The following does the trick
interface Bytes32 {
readonly length: 32;
}
class Bytes32 extends Uint8Array {
constructor() { super(32); }
}
This technique has a broad range of applications but also needs to be used with care.
Upvotes: 2