type DefineReplaceProperty<T, K extends keyof T, V>
outlines a function where the specific generic type parameters
T
,
K
, and
V
are predetermined. This particular function can only accept arguments of these pre-defined types
(i: T, k: K, v: V)
.
Essentially, it is a generic type that describes a non-generic function.
What you actually require is a generic function. Unlike a generic type, a generic function can be invoked with varying argument types. The type parameters T
, K
, and V
differ for each function call based on the arguments provided during the function call.
To resolve this, it is recommended to shift the generics to the other side of the equals sign:
type DefineReplaceProperty = <T, K extends keyof T, V>(
The type definition may be accurate, but errors may occur in your implementation of replaceProperty
due to TypeScript identifying a mismatch in return types.
Type '<T, K extends keyof T, V>(i: T, k: K, v: V) => T & { [x: string]: V; }' cannot be assigned to type 'DefineReplaceProperty'.
Type 'T & { [x: string]: V; }' is not compatible with type '{ [P in keyof T]: K extends P ? V : T[P]; }'
Introducing the dynamic property {[k]: v}
leads to the creation of a string index signature {[x: string]: V;}
To ensure correctness, utilizing as
for assertion might be necessary. Parenthesis are utilized to assert the type for the entire function rather than just the return value.
const replaceProperty = (<T, K extends keyof T, V>(
i: T,
k: K,
v: V
) => ({
...i,
[k]: v,
})) as DefineReplaceProperty;
However, creating a type specifically for the function instead of its arguments and return value may not always be necessary. An alternative approach would involve an inline declaration like so.
const replaceProperty1 = <T, K extends keyof T, V>(
i: T,
k: K,
v: V
) => ({
...i,
[k]: v,
}) as { [P in keyof T]: K extends P ? V : T[P] }
Typescript Playground Link