'`as const` alternative to narrow an array literal tuple, to avoid `readonly` modifiers

We use as const to narrow the types:

[ {foo: 'foo' }, { bar: 'bar' } ] as const

but this also adds readonly modifiers for all props and values. As of const this makes sens, but I would like to have the narrowing, without the readonly modifiers, as offen you want to modify the objects in tuple, or just pass it further to some method, which is of the same interface, but without deep readonly

let foo = [ {foo: 'foo' }, { bar: 'bar' } ]

here the foo is of type:

({
    foo: string;
    bar?: undefined;
} | {
    bar: string;
    foo?: undefined;
})[]

but I would expect to get

[{
    foo: string;
}, {
    bar: string;
}]

There for we use as const, but in most cases it is not possible, as foo/bar get deeply nested readonly modifiers, we could use something like

type DeepWritable<T> = { -readonly [P in keyof T]: DeepWritable<T[P]> };

But it would be wired to use as const which adds readonly, and then DeepWritable to remove it.

Do you know any alternative to as const to narrow the tuple type without having manually to define types.



Solution 1:[1]

You can use the following generic function to constrain the type as a tuple:

const Tuple = <T extends [any, ...any]>(v:T) => v

And then wrap the literal:

let foo = Tuple([ {foo: 'foo' }, { bar: 'bar' } ]) // foo: [{ foo: string }, { bar: string }]

Solution 2:[2]

Here is a better generic Tuple function, since it preserves tuple member literal values too:

export type Writable<T> = {
  -readonly [K in keyof T]: T[K];
};
export const Tuple = <T extends readonly [unknown, ...unknown[]]>(v: T) =>
  v as Writable<T>;

Use it like so:

const foo = Tuple([{foo: 'foo' }, { bar: 'bar' }] as const)
// foo: [{ readonly foo: 'foo' }, { readonly bar: 'bar' }]
// Note the array itself is not readonly, only the object properties are

See the relevant TypeScript 3.4 release note for reference.

Also worth checking out this related, more thorough answer

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ccarton
Solution 2