Reputation: 615
export type DraftObject<T> = {-readonly [P in keyof T]: Draft<T[P]>}
export interface DraftArray<T> extends Array<Draft<T>> {}
export type Draft<T> = T extends any[]
? DraftArray<T[number]>
: T extends ReadonlyArray<any>
? DraftArray<T[number]>
: T extends object ? DraftObject<T> : T
type tup = [number, number, number, number]
const T: Draft<tup> = [1, 2, 3, 4]
const U: tup = [1, 2, 3, 4]
const TT: tup = T
const UU: Draft<tup> = U
The type DraftObject should return any type with all its properties marked not read-only. This works in all cases, except tuple types, where they're incorrectly turned into arrays. How can I special case tuples, and Readonly<>
them instead of making them DraftArray
s?
Upvotes: 0
Views: 653
Reputation: 329388
If, for some reason, you need to detect the difference between tuples and arrays, you can use the fact that tuple types have a known "0"
key (the string value, not the number 0
) but arrays do not:
type IfTuple<T extends any[], Y=true, N=false> = "0" extends keyof T ? Y : N
type TestTuple = IfTuple<[string, number], "tuple", "array">; // "tuple"
type TestArray = IfTuple<string[], "tuple", "array">; // "array"
This should be enough to build a conditional type that does something different for tuples from what it does for general arrays.
Hope that helps. Good luck!
Upvotes: 3
Reputation: 30929
As jcalz said, there are no readonly tuples as of TypeScript 3.1. If you want to make everything mutable, you can just use:
export type Draft<T> = {-readonly [P in keyof T]: Draft<T[P]>};
taking advantage of the mapped tuples and arrays added in TypeScript 3.1 and the previously existing special case for homomorphic mapped types applied to primitives (Draft<T>
evaluates to T
when T
is primitive).
Upvotes: 3