Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArrayTag Generic Types #43

Open
Offroaders123 opened this issue Jan 4, 2024 · 2 comments
Open

ArrayTag Generic Types #43

Offroaders123 opened this issue Jan 4, 2024 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@Offroaders123
Copy link
Owner

Looking into a few different ways to accomplish representing tuple types with TypedArray-based NBT key types.

Right now the standard library types don't provide anything like tuple support for TypedArray values. I'd like to be able to do something like Int8Array<[number, number]>, and only allow access of those two properties, just like the regular Array tuple type notation allows for ([number, number] on it's own).

I've encountered a few places where this would be a great help at type validation, namely things like player NBT UUID fields, which would be IntArrayTag<[number, number, number, number]>, as well as position tuple fields, which tend to be what would be described with IntArrayTag<[number, number, number]>.

@Offroaders123 Offroaders123 added the enhancement New feature or request label Jan 4, 2024
@Offroaders123 Offroaders123 self-assigned this Jan 4, 2024
@Offroaders123
Copy link
Owner Author

Worked out yesterday how to accomplish this with a few builder types! It does everything I wanted to accomplish with it, and it really does help ensure type-safety. The only downside I've noticed with it so far though is that you can't validate with this type when you are creating a given TypedArray value, and you have to cast the value to meet the type. So this may be a one-way type help, because it would more be for the reading and editing of existing key values, rather than when defining new ones. I will think of how I can possible make this work, I feel like it should be doable somehow.

typescript - How to remove index signature using mapped types - Stack Overflow

type RemoveIndex<T extends object> = {
  [K in keyof T as
    string extends K
      ? never
      : number extends K
      ? never
      : symbol extends K
      ? never
      : K
  ] : T[K];
};

type ExtractTuple<T extends any[]> = {
  [Entry in keyof T as Entry extends `${number}` ? Entry : never]: T[Entry];
};

type ArrayTuple<TypedArray extends object, Tuple extends any[]> = RemoveIndex<TypedArray> & ExtractTuple<Tuple>;

type ArrayTag<ArrayLike extends object, Tuple extends any[] | ArrayLike> =
  Tuple extends any[]
    ? ArrayTuple<ArrayLike, Tuple>
    : ArrayLike;

type ByteArrayTag<T extends Int8Array[number][] | Int8Array = Int8Array> = ArrayTag<Int8Array, T>;

type IntArrayTag<T extends Int32Array[number][] | Int32Array = Int32Array> = ArrayTag<Int32Array, T>;

type LongArrayTag<T extends BigInt64Array[number][] | BigInt64Array = BigInt64Array> = ArrayTag<BigInt64Array, T>;

type Nice = ByteArrayTag;
type Nicer = ByteArrayTag<[number, 5]>;

declare const nice: Nice;
const hi = nice[110];

declare const nicer: Nicer;
// @ts-expect-error - `Array` methods shouldn't be present on this custom derived tuple type, since it's an `Int8Array`.
nicer.push;

const hello = nicer[1];
// @ts-expect-error - property shouldn't be indexable, it's not defined in the tuple generic.
nicer[5];

// Demos pt.2

// player position NBT type
type Pos = IntArrayTag<[number, number, number]>;

declare let pos: Pos;
pos[0];
pos[1];
pos[2];
// @ts-expect-error
pos[3];

// @ts-expect-error - this shouldn't be assignable to the tuple type
pos = new Int32Array() as IntArrayTag;

// comparing to regular tuple
type Lol = [0, 1, 2, 3];

declare const lol: Lol;
// @ts-expect-error - just like this isn't accessible
lol[5];

// Next demos after rehashing

// @ts-expect-error - How would one validate this, and get automatic type handling, withough needing to use `as` on the value? Can you add generics to existing interfaces?
const hii: LongArrayTag<[5n]> = new BigInt64Array([5n]);

@Offroaders123
Copy link
Owner Author

Here's another demo I was just writing to try out if this really does work well when embedded directly into NBTify.

ArrayTag Generic Demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant