Home > OS >  Preventing object literals type widening when passed as argument in TypeScript
Preventing object literals type widening when passed as argument in TypeScript

Time:08-13

Is is possible in the lastest TypeScript version to pass an object literal as argument to a function without widening it, and also without using as const in the invocation?

link to TS Playground: Example

What I currently do is this:

function func<T>(value: T): T { 
    return value;
};

let test = func({ key: 'value' })
// type inferred as { key: string;}

what I want is the following

// ... alternative declaration of func

let test = func({ key: 'value' })
// type inferred as { key: "value"; }

More precisely it should work for any object literal extending Record<string,string>

These archive the result I want, but Id like not to change the way the function must be invoked

function func<T>(value: T): T {
    return value
};

let test = func({ key: 'value' as const })
// type inferred as { key: "value"; }

let test = func({ key: 'value' } as const )
// type inferred as { readonly key: "value"; }

Is this possible?

CodePudding user response:

Yes, this is possible. But the solution might seem unintuitive and redundant.

You will have to add another generic type to the function. This will keep will allow us to keep narrowed type of string literals passed to the function.

function func<T extends Record<string, S>, S extends string>(value: T): T { 
    return value;
};

let test = func({ key: 'value', a: "a" })
// let test: {
//     key: "value";
//     a: "a";
// }

We can apply this to your complex example.

declare function formatMessage<
  Key extends keyof typeof messages, 
  Props extends { [key: string]: S }, 
  S extends string
>(messageKey: Key, props?: Props)
    :ReplaceValues<(typeof messages)[Key],  NonNullable<typeof props>>;

let test4 = formatMessage("created", {name: "TestValue"})
// let test4: "TestValue was created successfully."

Playground


Here are some further resources which helped me with problems like these in the past.

  • Related