#reverse const assertion / remove readonly from variables

38 messages · Page 1 of 1 (latest)

vague fiber
#

Is there a way to reverse const assertion on variables, and remove the readonly?
for example:

const arr = ["a", "b"] as const; // type of arr is `readonly ["a", "b"]`
const arr2 = arr as -readonly (typeof arr); // type of arr2 would be `["a", "b"]`
cloud cedar
#

A writable array cannot be type ["a", "b"], because it can be updated, changing it's contents

#

The type of a variable isn't it's current value, but its acceptable values

#

also arr2 refers to the same array as arr, so if you update arr2 it will update arr, breaking the readonly restriction

sand bloomBOT
#
sandiford#0

Preview:ts const arr = ["a", "b"] as const // ^? const arr2 = [...arr] // ^?

cloud cedar
#

You can do this

#
const arr = ["a", "b"] as const; // readonly ["a", "b"]
const arr2 = [...arr] // ("a" |"b")[]
#

@vague fiber

vague fiber
#

Thanks @cloud cedar , my usage is actually not to modify the the second array, and is mostly to satisfy other condition (something like a function that accept ("a" | "b")[] but wont accept a readonly array), I'll try to destruct to a new array instead

cloud cedar
#

oh just cast it

#

func(arr as ("a" | "b")[])

#

Technically the other function should declare that it takes readonly arrays, which guarantees that it does not modify it

#

But if you are certain that it only reads, and just has not been typed correctly, then you can cast

#

you can probably also redeclare the type of the func somehow

sand bloomBOT
#
sandiford#0

Preview:```ts
function foo(arr: ("a" | "b")[]) {}
const tuple = ["a", "b"] as const

foo(tuple as unknown as ("a" | "b")[])

type RealFoo = (arr: readonly ("a" | "b")[]) => void
;(foo as RealFoo)(tuple)```

cloud cedar
#

Here are 2 options

vague fiber
#

Thanks @cloud cedar ! I will probably use the second one, I don't like using as unknown as usually, feels a but like cheating or like using any

#

!solved

cloud cedar
#

it's not as unknown really, its just a hack so typescript will let us cast to ("a" | "b")[]

#

tuple as unknown as ("a" | "b")[] is tuple as ("a" | "b")[]

#

casting to unknown isn't* really dangerous anyway, as it says we know nothing and will usually throw up a lot of errors. Casting to any is the total opposite of that, as it just disables checking

#

But yeah i think the second one is better

sand bloomBOT
#
sandiford#0

Preview:```ts
import {foo as _foo} from "foo"
type RealFoo = (arr: readonly ("a" | "b")[]) => void
const foo = _foo as RealFoo

const tuple = ["a", "b"] as const

foo(tuple)```

cloud cedar
#

here's a cleaner way

#

You can take it further to the point of point the RealFoo stuff in a module, so you just import from your own cleanup module

#
import { foo } from './clean-foo.js'
#

Obviously if you can contacat the auther and give them to fix the types that is even better : )

solid storm
#

being a tuple and being readonly are separate things

solid storm
#

it is effectively a non-infectious as any

cloud cedar
#

Right

#

so the compiler was highlighting my error, can just do

foo(tuple as ['a', 'b'])
#

Now I'm curious. Mapping a type preserves the readonly status, which suggests that readonly is a property of the entries not the object

type WritableTuple<X extends readonly [...unknown[]]> = {
    [K in keyof X]: X[K]
}

type W = WritableTuple<readonly ['a', 'b']>
type W2 = WritableTuple<['a', 'b']>
sand bloomBOT
#
sandiford#0

Preview:```ts
type WritableTuple<X extends readonly [...unknown[]]> =
{
-readonly [K in keyof X]: X[K]
}

type W = WritableTuple<readonly ["a", "b"]>```

cloud cedar
#

@vague fiber Here you go. Here's the solution to what you asked, thanks to some prompting by @solid storm : )

vague fiber
#

Yes that is the solution, would love in the future for typescript to have -readonly or -? on non objects

cloud cedar
#

?