Skip to content

Instantly share code, notes, and snippets.

@LinusBorg
Last active March 7, 2022 10:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LinusBorg/9655c01e99fb609bac1f5d228e8174f9 to your computer and use it in GitHub Desktop.
Save LinusBorg/9655c01e99fb609bac1f5d228e8174f9 to your computer and use it in GitHub Desktop.
Experimenting with how to deeply un-readonly a type
type Primitive = string | number | boolean | bigint | symbol | undefined | null
type Builtin = Primitive | Function | Date | Error | RegExp
type UnReadOnly<T> = {
-readonly [K in keyof T]:
T[K] extends Builtin
? T[K]
: T[K] extends Ref<infer U>
? Ref<UnReadOnly<U>>
: T[K] extends ReadonlySet<infer U>
? Set<UnReadOnly<U>>
: T[K] extends Set<infer U>
? Set<UnReadOnly<U>>
: T[K] extends ReadonlyMap<infer U, infer V>
? Map<U, UnReadOnly<V>>
: T[K] extends Map<infer U, infer V>
? Map<U, UnReadOnly<V>>
: T[K] extends object ? UnReadOnly<T[K]> : T[K]
}
type Test = {
readonly name: string,
readonly age: number,
readonly children: string[],
readonly address: {
readonly street: string
readonly zip: number
readonly city: string
},
readonly items: ReadonlySet<string>
readonly someref: Ref<string>
}
const test: Test = {
name: 'Tom',
age: 40,
children: ['Tick', 'Trick', 'Track'],
address: {
street: 'main St.'
zip: 12345,
city: 'LA'
},
items: new Set(),
someref: { value: 'hello' } as unknown as Ref<string>
}
// Readonly object:
test.address.street = 'Jerry'
test.items.add('stuff')
// removing readonly from all nested types
const test2: UnReadOnly<typeof test> = test
// mutable object, also for all neste properties
test2.address.city = 'london'
test2.children.push('Lisa')
test2.items.add('')
// Ref types only for exerimenting, normally defined in Vue core.
declare const RefSymbol: unique symbol
interface Ref<T = any> {
value: T
/**
* Type differentiator only.
* We need this to be in public d.ts but don't want it to show up in IDE
* autocomplete, so we use a private Symbol instead.
*/
[RefSymbol]: true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment