Search code examples
typescriptobjectgenericstypes

Explicitly infer object as readonly


I have a function which takes in an object

declare function f<T extends object>(body: T): any;

f({
  type: "object",
})

Function signature looks like this:

function f<{
    type: string;
}>(body: {
    type: string;
}): any

But i expect it to be:

function f<{
    type: "object";
}>(body: {
    type: "object";
}): any

without actually using as const when passing the object.

Is there any way I can infer the object type explicitly as readonly?


Solution

  • You can use a const type parameter to indicate a preference for const-assertion-like inference:

    declare function f<const T extends object>(body: T): any;
    
    f({ type: "object" })
    /* function f<{ readonly type: "object"; }>(
        body: { readonly type: "object"; }
    ): any */
    

    Here the type of the object literal { type: "object" } has been inferred as { readonly type: "object" }, without needing an explicit as const.

    Thus the type property is both readonly and a string literal type.

    The question as asked doesn't seem to distinguish between readonly and literal properties, so I guess it doesn't matter much here. But note that in general readonly properties don't need to be of literal types and literal typed properties don't need to be readonly:

    const readonlyNotLiteral: { readonly a: string } = { a: "abc" };
    readonlyNotLiteral.a = "def"; // error
    readonlyNotLiteral.a = "abc"; // error
    
    const literalNotReadonly: { a: "abc" } = { a: "abc" };
    literalNotReadonly.a = "def"; // error
    literalNotReadonly.a = "abc"; // okay
    

    Playground link to code