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."
Here are some further resources which helped me with problems like these in the past.
Suggestion: Const contexts for generic type inference - This post describes a way to narrow down object literals of arbitrary shape.