-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Suggestion: a built-in TypedArray interface #15402
Comments
You can achieve the same behavior today by defining: type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; but in general define one TypedArray interface and use |
@mhegazy Yes, that's the solution I'm using now, but it seems a bit unnecessary. I'll submit a PR shortly. |
Resolves microsoft#15402 Changes: - Adds a TypedArray declaration to the built-in declaration libraries from which Int8Array, etc, inherit - Fixes the find() and findIndex() methods so that the third argument of the callback is `this` rather than `Array<number>` Further issues: - The NodeBuffer interface (and hence Buffer) in @types/node is incompatible with the above changes; submitted a PR at DefinitelyTyped/DefinitelyTyped#microsoft#16161
Would asking for types for 0x, 0b, and 0o be a different request on this? The reason I would like these type is to use with TypedArrays. Currently there is no guard on inserting any number into those typedArrays. Which shouldn't be allowed. Lets say you wanted to put a value 255 into a Int8Array field, this should have a type guard for type int8 = -0x80 to 0x7F | -0b10000000 to 0b1111111 | -0o200 to 0o177
type hex = any 0xFFFFF...;
type binary = any 0b1001010101...;
type octal = any 0o17235...; Something that would prevent a programmer from inserting numbers that will be converted within the typed arrays. |
@marcusjwhelan That is a very different proposal, and far beyond the scope of this one. This is just about adding another interface to the declaration files, not about introducing new syntax. |
There already is ArrayBufferView interface in lib.d.ts for this exact purpose, which is a supertype of all typed arrays. interface ArrayBufferView {
/**
* The ArrayBuffer instance referenced by the array.
*/
buffer: ArrayBuffer;
/**
* The length in bytes of the array.
*/
byteLength: number;
/**
* The offset in bytes of the array.
*/
byteOffset: number;
}
interface ArrayBufferConstructor {
readonly prototype: ArrayBuffer;
new (byteLength: number): ArrayBuffer;
isView(arg: any): arg is ArrayBufferView;
}
declare const ArrayBuffer: ArrayBufferConstructor;
ArrayBuffer.isView(new Uint8Array()); // true On Web IDL: typedef (Int8Array or Int16Array or Int32Array or
Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or
Float32Array or Float64Array or DataView) ArrayBufferView; |
The solution that @mhegazy gives might be okay in some cases. But I'm writing code that is something like this: type Arr<T> = T[] | Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;
function isSame<T>(first: Arr<T>, second: Arr<T>) {
return first.every((ele: T, index: number): boolean => {
return ele === second[index];
});
} And it just will not compile because every has this type def (it is copied for each type of array): every(callbackfn: (this: void, value: number, index: number, array: Float64Array) => boolean): boolean; |
FWIW, I have this concept in my library as I have to deal with TypedArrays a lot, see: I also made a TS fork of gl-matrix (https://github.com/stardazed/veclib) where I often had to deal with TypedArray or array inputs being returned and wanting TS to deduce the right return type, solved like so: type AN = ArrayOfNumber; // an ArrayLike<number> with non-readonly subscript
type ACN = ArrayOfConstNumber; // ArrayLike<number>
export function min(out: number[], a: ACN, b: ACN): number[];
export function min<T extends AN>(out: T, a: ACN, b: ACN): T;
export function min(out: AN, a: ACN, b: ACN) { ...code... } This allows it to return the correct type info for both: const a = min([], [1,2,3], [3,2,1]); // a: number[]
const b = min(new Int32Array(3), [1,2,3], [3,2,1]); // b: Int32Array |
previous: ``` PS C:\Users\aval\tsdev\TypeScript> node built\local\tsc.js --diagnostics --p src\compiler\tsconfig.json Files: 36 Lines: 93186 Nodes: 445312 Identifiers: 168285 Symbols: 71668 Types: 32088 Memory used: 371617K I/O read: 0.02s I/O write: 0.17s Parse time: 0.71s Bind time: 0.62s Check time: 2.90s Emit time: 2.06s Total time: 6.29s ``` now: ``` PS C:\Users\aval\tsdev\TypeScript> node built\local\tsc.js --diagnostics --p src\compiler\tsconfig.json Files: 36 Lines: 91099 Nodes: 439748 Identifiers: 166769 Symbols: 71022 Types: 31979 Memory used: 369763K I/O read: 0.02s I/O write: 0.03s Parse time: 0.69s Bind time: 0.59s Check time: 2.92s Emit time: 1.89s Total time: 6.09s ``` Fixes microsoft#15402
previous: ``` PS C:\Users\aval\tsdev\TypeScript> node built\local\tsc.js --diagnostics --p src\compiler\tsconfig.json Files: 36 Lines: 93186 Nodes: 445312 Identifiers: 168285 Symbols: 71668 Types: 32088 Memory used: 371617K I/O read: 0.02s I/O write: 0.17s Parse time: 0.71s Bind time: 0.62s Check time: 2.90s Emit time: 2.06s Total time: 6.29s ``` now: ``` PS C:\Users\aval\tsdev\TypeScript> node built\local\tsc.js --diagnostics --p src\compiler\tsconfig.json Files: 36 Lines: 91099 Nodes: 439748 Identifiers: 166769 Symbols: 71022 Types: 31979 Memory used: 369763K I/O read: 0.02s I/O write: 0.03s Parse time: 0.69s Bind time: 0.59s Check time: 2.92s Emit time: 1.89s Total time: 6.09s ``` Fixes microsoft#15402
previous: ``` PS C:\Users\aval\tsdev\TypeScript> node built\local\tsc.js --diagnostics --p src\compiler\tsconfig.json Files: 36 Lines: 93186 Nodes: 445312 Identifiers: 168285 Symbols: 71668 Types: 32088 Memory used: 371617K I/O read: 0.02s I/O write: 0.17s Parse time: 0.71s Bind time: 0.62s Check time: 2.90s Emit time: 2.06s Total time: 6.29s ``` now: ``` PS C:\Users\aval\tsdev\TypeScript> node built\local\tsc.js --diagnostics --p src\compiler\tsconfig.json Files: 36 Lines: 91099 Nodes: 439748 Identifiers: 166769 Symbols: 71022 Types: 31979 Memory used: 369763K I/O read: 0.02s I/O write: 0.03s Parse time: 0.69s Bind time: 0.59s Check time: 2.92s Emit time: 1.89s Total time: 6.09s ``` Fixes microsoft#15402
previous: ``` PS C:\Users\aval\tsdev\TypeScript> node built\local\tsc.js --diagnostics --p src\compiler\tsconfig.json Files: 36 Lines: 93186 Nodes: 445312 Identifiers: 168285 Symbols: 71668 Types: 32088 Memory used: 371617K I/O read: 0.02s I/O write: 0.17s Parse time: 0.71s Bind time: 0.62s Check time: 2.90s Emit time: 2.06s Total time: 6.29s ``` now: ``` PS C:\Users\aval\tsdev\TypeScript> node built\local\tsc.js --diagnostics --p src\compiler\tsconfig.json Files: 36 Lines: 91099 Nodes: 439748 Identifiers: 166769 Symbols: 71022 Types: 31979 Memory used: 369763K I/O read: 0.02s I/O write: 0.03s Parse time: 0.69s Bind time: 0.59s Check time: 2.92s Emit time: 1.89s Total time: 6.09s ``` Fixes microsoft#15402
It seems like @saschanaz has the correct answer, and this issue can be closed |
Wait, just kidding:
|
Unfortunately, I think adding an interface for TypedArray might be a bad idea. TypedArray is a weird JavaScript constructor, which is why I think TypeScript is correct to avoid implementing a regular interface for it. As an alternative, I suggest adding I found this thread after I read about TypedArrays on MDN then tried to write However, TypedArray is a constructor, it's just not (usually) a visible one, which is why 1 "[object Object]" "Int16Array" TypedArray {constructor: ƒ, BYTES_PER_ELEMENT: 2}
2 "[object Object]" "TypedArray" {constructor: ƒ, …}
3 "[object Object]" "Object" {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} According to MDN "There is no global property named TypedArray, nor is there a directly visible TypedArray constructor." (I admit I don't fully understand what it means to be an "invisible" constructor. I understand why JavaScript doesn't allow I might argue that it would make more sense for JavaScript to implement TypedArray as an normal constructor, the way 1 "[object File]" "File" File {constructor: ƒ, …}
2 "[object Blob]" "Blob" Blob {slice: ƒ, constructor: ƒ, Symbol(Symbol.toStringTag): "Blob"}
3 "[object Object]" "Object" {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} So However, until JavaScript makes TypedArray a normal constructor, I don't think TypeScript should implement an interface for it. Doing so might confuse users, who would then expect TypedArray to behave like other JavaScript constructors, which it does not. As an alternative, I recommend adding |
I get why we should not write something like Writing something like Using a common interface for TypedArrays would remove redundant declaration and would not imply that ArrayBufferView might be a solution but I'm not familiar with Web IDL and I never seen this type before. I always saw |
|
What about a common interface for typed and untyped arrays? I have already published this type. You can take a look at the project page: typeable-array. |
@saschanaz does not work. It lacks most functionality that a typed array would have such as length or even member access. The reason is that this interface is meant to be used for any view of arraybuffer. So DataView is also included. |
I seriously don't see a problem with introducing an interface called To enable a TypeScript-native (unhacky) abstraction for numerically typed arrays, I strongly recommend the introduction of a |
@dschnelldavis
As other people have said, even though it's an invisible constructor, there should still be an interface for it, as it encapsulates a lot of functionality in a single base class and drastically reduces repetition for definition files, as well as more accurately reflecting the specification. I think there should also be an interface for
|
Has there been progress along this avenue? |
Another example - node has fs.writeFile which accepts It would be really nice to have this one and change |
How about defining it as follows? example-typed-array.d.tsinterface TypedArray<N extends number | bigint> {
// defined in `lib.es5.d.ts`
readonly BYTES_PER_ELEMENT: number;
readonly buffer: ArrayBufferLike;
readonly byteLength: number;
readonly byteOffset: number;
copyWithin(target: number, start: number, end?: number): this;
every(predicate: (value: N, index: number, array: this) => unknown, thisArg?: any): boolean;
fill(value: N, start?: number, end?: number): this;
filter(predicate: (value: N, index: number, array: this) => any, thisArg?: any): this;
find(predicate: (value: N, index: number, obj: this) => boolean, thisArg?: any): N | undefined;
findIndex(predicate: (value: N, index: number, obj: this) => boolean, thisArg?: any): number;
forEach(callbackfn: (value: N, index: number, array: this) => void, thisArg?: any): void;
indexOf(searchElement: N, fromIndex?: number): number;
join(separator?: string): string;
lastIndexOf(searchElement: N, fromIndex?: number): number;
readonly length: number;
map(callbackfn: (value: N, index: number, array: this) => N, thisArg?: any): this;
reduce(callbackfn: (previousValue: N, currentValue: N, currentIndex: number, array: this) => N): N;
reduce<U>(callbackfn: (previousValue: U, currentValue: N, currentIndex: number, array: this) => U, initialValue: U): U;
reduceRight(callbackfn: (previousValue: N, currentValue: N, currentIndex: number, array: this) => N): N;
reduceRight<U>(callbackfn: (previousValue: U, currentValue: N, currentIndex: number, array: this) => U, initialValue: U): U;
reverse(): this;
set(array: ArrayLike<N>, offset?: number): void;
slice(start?: number, end?: number): this;
some(predicate: (value: N, index: number, array: this) => unknown, thisArg?: any): boolean;
sort(compareFn?: (a: N, b: N) => number | bigint): this;
subarray(begin?: number, end?: number): this;
toLocaleString(): string;
toString(): string;
valueOf(): this;
[index: number]: N;
// defined in `lib.es2015.iterable.d.ts`
[Symbol.iterator](): IterableIterator<N>;
entries(): IterableIterator<[number, N]>;
keys(): IterableIterator<number>;
values(): IterableIterator<N>;
// defined in `lib.es2016.array.includes.d.ts`
includes(searchElement: N, fromIndex?: number): boolean;
}
interface Int8Array extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 1;
readonly [Symbol.toStringTag]: 'Int8Array';
}
interface Uint8Array extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 1;
readonly [Symbol.toStringTag]: 'UInt8Array';
}
interface Uint8ClampedArray extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 1;
readonly [Symbol.toStringTag]: 'Uint8ClampedArray';
}
interface Int16Array extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 2;
readonly [Symbol.toStringTag]: 'Int16Array';
}
interface Uint16Array extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 2;
readonly [Symbol.toStringTag]: 'Uint16Array';
}
interface Int32Array extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 4;
readonly [Symbol.toStringTag]: 'Int32Array';
}
interface Uint32Array extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 4;
readonly [Symbol.toStringTag]: 'Uint32Array';
}
interface Float32Array extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 4;
readonly [Symbol.toStringTag]: 'Float32Array';
}
interface Float64Array extends TypedArray<number> {
readonly BYTES_PER_ELEMENT: 8;
readonly [Symbol.toStringTag]: 'Float64Array';
}
interface BigInt64Array extends TypedArray<bigint> {
readonly BYTES_PER_ELEMENT: 8;
readonly [Symbol.toStringTag]: 'BigInt64Array';
}
interface BigUint64Array extends TypedArray<bigint> {
readonly BYTES_PER_ELEMENT: 8;
readonly [Symbol.toStringTag]: 'BigUint64Array';
} |
TypedArray is a standard built-in type per JS specification. Does this mean it must have its own separate definition somewhere in standard types? |
I've ran into issues with this in circumstances like this/ type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray
| Int16Array | Uint16Array
| Int32Array | Uint32Array
| BigInt64Array | BigUInt64Array
| Float32Array | Float64Array
function expand<T extends TypedArray>(arr: T, elementCount: number): T {
const constructor = arr.constructor as new (length: number) => T
const result = new constructor(arr.length + elementCount)
result.set(arr) //error: TypedArray.set requires first parameter of type ArrayLike<number> & ArrayLike<bigint>
return result
} |
Each concrete typed array type and constructor share common interfaces. Library types can be defined extending base interfaces: 1. higher code reuse 2. less duplication 3. easier maintenance (less error prone) Closes microsoft#15402 Fixes microsoft#45198
Each concrete typed array type and constructor share common interfaces. Library types can be defined extending base interfaces: 1. higher code reuse 2. less duplication 3. easier maintenance (less error prone) Closes microsoft#15402 Fixes microsoft#45198
Each concrete typed array type and constructor share common interfaces. Library types can be defined extending base interfaces: 1. higher code reuse 2. less duplication 3. easier maintenance (less error prone) Closes microsoft#15402 Fixes microsoft#45198
Each concrete typed array type and constructor share common interfaces. Library types can be defined extending base interfaces: 1. higher code reuse 2. less duplication 3. easier maintenance (less error prone) Closes microsoft#15402 Fixes microsoft#45198
In @types/node, |
I would have expected a
TypedArray
interface to exist inthe built-in declaration libraries. Instead, there are independent types for
Int8Array
, etc, with no common base type.It seems sensible that there should be a common
TypedArray
type, both becauseTypedArray
, andIs there a good reason why there is no
TypedArray
type? If not, I can submit a PR.Use case
Consider the
isTypedArray()
function from lodash.Currently, it is declared as follows:
This proposal would enable an appropriate type-guard, without declaring
a convoluted union type:
The text was updated successfully, but these errors were encountered: