Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Preventing object literals type widening when passed as argument in TypeScript

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading