You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@arrow.apache.org by "DadiBit (via GitHub)" <gi...@apache.org> on 2025/08/09 19:59:41 UTC

[D] Better type safety schemas [arrow-js]

GitHub user DadiBit created a discussion: Better type safety schemas

Greetings, I just started exploring Arrow and DuckDB, and I must admit it's quite interesting, however... I was hurting a bit to not be able to get full type safety with typescript intellisense of vscodium. I saw #192, and it looks somewhat related.
When I request the fields I just end up with an array of fields... Meh, having a typed object would be much cooler, wouldn't it?

Here's how I partially implemented my type safety:

##### `helper.ts` allows me to infer the constructor params as tuples:
```typescript
import { Schema, Field } from "@apache-arrow/ts";

// See: https://stackoverflow.com/a/55344772
type Tail<T extends any[]> = T extends [infer A, ...infer R] ? R : never;
export type Fields = { [name: string]: Tail<ConstructorParameters<typeof Field>> };
type FieldsTypeMap<T extends Fields> = { [K in keyof T]: T[K][0] };

// Factory to generate typed schema
export function schemaFactory<T extends Fields>(fields: T) {
  const _fields = Object.entries(fields).map(([name, field]) => new Field(name, ...field));
  return new Schema<FieldsTypeMap<T>>(_fields);
}
```

##### `student.ts` to check out intellisense
```typescript
import { Uint8, Utf8 } from "@apache-arrow/ts";
import { Fields, schemaFactory } from "./helper";

export const fields = {
  // here it fails to help me with names, but types are checked, that's something!
  'name': [new Utf8(), true],
  'age': [new Uint8(), true],
} satisfies Fields; // satisfies is very import, it doesn't erase the keys!

// Now, `schema`, techincally has the generic specific for my type
// When using `.fields` you get something out of it: 
// But it's just Field<Utf8 | Uint8>[]... What the hell, I lose some information, namely the key!
export const schema = schemaFactory(fields);
```

So I would like to ask if there's any chance to modify the library to return more meaningful types. This **would break some code**, since the types returned would change and some dev might depend on the type defintions (altough not super useful).

GitHub link: https://github.com/apache/arrow-js/discussions/232

----
This is an automatically sent email for user@arrow.apache.org.
To unsubscribe, please send an email to: user-unsubscribe@arrow.apache.org


Re: [D] Better type safety schemas [arrow-js]

Posted by "DadiBit (via GitHub)" <gi...@apache.org>.
GitHub user DadiBit added a comment to the discussion: Better type safety schemas

_First of all, thanks for the crazy quick reply: first time that happens to me in an open source project!_

I like that DuckDB allows me to access static datasets, however as domortiz stated, the moment I started working on my frontend I realized I had no typescript checking (just the good old `tsc` blindly using `any` type).

I have very little knowledge on the underlying library structure, but I'm pretty sure some refactoring will be required. I would start by proposing a change that shouldn't brake anything, and is super easy to implement: let the `Schema` constructor accept a typed dictionary like:
```typescript
const schema = new Schema({
  'name': new AnonymousField(...args...),
  'age': new AnonymousField(...args...),
}, ...args...)
```

This would simply call `new Field(key, ...args...)` under the hood, just like my example.
This is simple and won't need much testing, but next part is better, if it gets properly tested (as it's a bit more complex).

---
Checking the Field class:
https://github.com/apache/arrow-js/blob/90c1db18cff5755b586bd8978c73aaa990770626/src/schema.ts#L106-L146

It looks to me we could get away with a simple dictionary with a `{...args...} as const as IAnonField`:
```
interface IAnonField<T> {
  name: string,
  type: T,
  nullable?: boolean,
  // This also is a bit sus, Why allow null *and* udnefined? Is it intended? Idk...
  metadata?: Map<string, string> | null
}

const x = { type: arrow.Int32 } as const satisfies IAnonField;
x.type; // this should show arrow.Int32 when hovering over it in vscodium
```
This means we let typescript know the field type, which is actually a value available at runtime in the javascript engine. I'll try working on this tomorrow instead, looks super promising :smile: 

GitHub link: https://github.com/apache/arrow-js/discussions/232#discussioncomment-14060153

----
This is an automatically sent email for user@arrow.apache.org.
To unsubscribe, please send an email to: user-unsubscribe@arrow.apache.org


Re: [D] Better type safety schemas [arrow-js]

Posted by "domoritz (via GitHub)" <gi...@apache.org>.
GitHub user domoritz added a comment to the discussion: Better type safety schemas

We regularly make new major releases and stricter types are usually good as they avoid bugs. 

GitHub link: https://github.com/apache/arrow-js/discussions/232#discussioncomment-14059736

----
This is an automatically sent email for user@arrow.apache.org.
To unsubscribe, please send an email to: user-unsubscribe@arrow.apache.org


Re: [D] Better type safety schemas [arrow-js]

Posted by "kou (via GitHub)" <gi...@apache.org>.
GitHub user kou added a comment to the discussion: Better type safety schemas

FYI: We can change the release cycle because we split the JS implementation from apache/arrow. We can release a new major version only when we need. We can release minor/patch versions when we need.

GitHub link: https://github.com/apache/arrow-js/discussions/232#discussioncomment-14059930

----
This is an automatically sent email for user@arrow.apache.org.
To unsubscribe, please send an email to: user-unsubscribe@arrow.apache.org


Re: [D] Better type safety schemas [arrow-js]

Posted by "DadiBit (via GitHub)" <gi...@apache.org>.
GitHub user DadiBit added a comment to the discussion: Better type safety schemas

> Note: Javascript objects [do not guarantee insertion order](https://stackoverflow.com/a/23202095/9373031) IF the key type differs (I see both strings and numbers are allowed in the same schema - like a field named `1` and one named `"name"`)

Example of writer that uses both strings and numbers as keys (Symbols are not supported, so we don't even need to work with them):
```typescript
// write.js
import { tableToIPC, Schema, Field, Uint8, Float32, Table, makeData, vectorFromArray } from 'apache-arrow';
import * as fs from 'fs';

const schema = new Schema([
    new Field('precipitations', new Float32()),
    new Field('0', new Uint8()),
]);

const table = new Table(schema, {
    age: makeData({ type: new Float32(), length: 3, data: vectorFromArray([1, 2, 3.14]) }),
    0: makeData({ type: new Uint8(), length: 3, data: vectorFromArray([7, 8, 9]) }),
});

fs.writeFileSync('simple.arrow', tableToIPC(table, 'file'));
```

And then, if we read we can see column order retention:
```typescript
// read.js
import { tableFromIPC } from 'apache-arrow';
import * as fs from 'fs';

const table = tableFromIPC(fs.readFileSync('simple.arrow'));

console.log(table.schema.fields);
// Now you should see that the field '0' comes after 'precipitations', "not standard", but expected behavior IMHO
```

With that said, if we look into the friendlier `makeTable` & Co. the result is that objects are used from the get-go. So field order isn't crucial, from my understanding, however the underlying structure should probably respect it.

---

See PR #233

GitHub link: https://github.com/apache/arrow-js/discussions/232#discussioncomment-14063251

----
This is an automatically sent email for user@arrow.apache.org.
To unsubscribe, please send an email to: user-unsubscribe@arrow.apache.org