Skip to content

Commit a92e393

Browse files
committed
infer fields with no setter as readonly
1 parent 34481d1 commit a92e393

4 files changed

Lines changed: 56 additions & 10 deletions

File tree

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@rotu/structview",
3-
"version": "0.11.1",
3+
"version": "0.12.0",
44
"license": "MIT",
55
"tasks": {
66
"dev": "deno test --watch",

fields.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { structBytes, structDataView } from "./core.ts"
77
import type {
8+
ReadOnlyAccessorDescriptor,
89
StructConstructor,
910
StructPropertyDescriptor,
1011
TypedArraySpecies,
@@ -277,7 +278,7 @@ export function bool(fieldOffset: number): StructPropertyDescriptor<boolean> {
277278
*/
278279
export function fromDataView<T>(
279280
fieldGetter: (dv: DataView) => T,
280-
): StructPropertyDescriptor<T> {
281+
): StructPropertyDescriptor<T> & ReadOnlyAccessorDescriptor<T> {
281282
return {
282283
get() {
283284
const dv = structDataView(this)
@@ -299,7 +300,7 @@ export function substruct<
299300
ctor: StructConstructor<T>,
300301
byteOffset?: number,
301302
bytelength?: number,
302-
): StructPropertyDescriptor<T> {
303+
): StructPropertyDescriptor<T> & ReadOnlyAccessorDescriptor<T> {
303304
return fromDataView(
304305
function (dv) {
305306
const offset2 = dv.byteOffset + (byteOffset ?? 0)
@@ -332,7 +333,7 @@ export function typedArray<T>(
332333
/** TypedArray constructor */
333334
readonly species: TypedArraySpecies<T>
334335
},
335-
): StructPropertyDescriptor<T> {
336+
): StructPropertyDescriptor<T> & ReadOnlyAccessorDescriptor<T> {
336337
const { length, species } = kwargs
337338
return {
338339
get() {

mod_test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,30 @@ Deno.test("typedArray", () => {
397397
const f32s2 = new Float32Array([1 / 3, 1 / 6, 1 / 9])
398398
assertEquals(new Float32Array(buf.buffer.slice(4, 16)), f32s2)
399399
})
400+
401+
Deno.test("getter-only properties inferred as readonly", () => {
402+
class S extends defineStruct({
403+
y: {
404+
get() {
405+
return 42
406+
},
407+
},
408+
z: typedArray(9, { species: Uint8Array, length: 3 }),
409+
s: substruct(Struct, 0),
410+
}) {}
411+
const obj = new S(new Uint8Array(10))
412+
413+
// note: this test is about the type assertions
414+
assertThrows(() => {
415+
// @ts-expect-error assigning to readonly property
416+
obj.y = 1
417+
})
418+
assertThrows(() => {
419+
// @ts-expect-error assigning to readonly property
420+
obj.z = new Uint8Array()
421+
})
422+
assertThrows(() => {
423+
// @ts-expect-error assigning to readonly property
424+
obj.s = {}
425+
})
426+
})

types.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,38 @@ export type TPropertyDescriptor<T> = {
3232
}
3333

3434
/**
35-
* Object type that would result from Object.defineProperties(p:Props)
35+
* Object type that would result from Object.defineProperties({}, p:Props)
3636
*/
37-
export type MixinFromProps<Props extends object> = {
38-
-readonly [K in keyof Props]: Props[K] extends TPropertyDescriptor<infer V>
39-
? V
40-
: unknown
41-
}
37+
export type MixinFromProps<Props extends object> =
38+
& {
39+
+readonly [
40+
K
41+
in keyof Props as (Props[K] extends ReadOnlyAccessorDescriptor<unknown>
42+
? K
43+
: never)
44+
]: Props[K] extends TPropertyDescriptor<infer V> ? V : unknown
45+
}
46+
& {
47+
-readonly [
48+
K
49+
in keyof Props as (Props[K] extends ReadOnlyAccessorDescriptor<unknown>
50+
? never
51+
: K)
52+
]: Props[K] extends TPropertyDescriptor<infer V> ? V : unknown
53+
}
4254

4355
/**
4456
* Type of a property descriptor for a struct
4557
*/
4658
export type StructPropertyDescriptor<T> =
4759
& ThisType<AnyStruct>
4860
& TPropertyDescriptor<T>
61+
62+
export type ReadOnlyAccessorDescriptor<T> = {
63+
get(): T
64+
set?: undefined
65+
}
66+
4967
export type StructConstructor<T extends object> = {
5068
new (arg: {
5169
readonly buffer: ArrayBufferLike

0 commit comments

Comments
 (0)