Reputation: 63540
interface A { a?: number };
interface B { a?: string };
function copy<
Source extends object,
Destination extends { [destinationKey in keyof Source]?: (1) }
>(
source: Source,
key: keyof Source,
destination: Destination,
transformer: (value: (2)) => (3)
) {
if (source[key] !== undefined) {
destination[key] = transformer ? transformer(source[key]) : source[key];
}
}
const a: A = { a: 123 };
const b: B = {};
copy(a, "a", b, (value) => value.toString());
In the above example, what can I use for the following placeholders:
Destination
associated with the corresponding key in Source
.Source
associated with the key specified by parameter key
.Destination
associated with the key specified by parameter key
.Upvotes: 1
Views: 201
Reputation: 250106
You need an extra type parameter representing the actual key that will be passed in. This parameter will be inferred to a string literal type based on the value passed in to the key
parameter. With this new type we can use type queries to get the specific property in type in the Source
and Destination
types.
Also since we only care about the specific K
key we can use it when we defined the Destination
type as having it (instead of specifying that Destination
must have all keys of Source
). Since we don't really care about the type of the destination property, just that it exists and that the transformer
function must return a value of the same type as this property we can just specify the type of the property in Destination
as unknown
.
interface A { a?: number };
interface B { a?: string };
function copy<
K extends keyof Source, // The extra type parameter
Source extends object,
Destination extends { [destinationKey in K]?: unknown } // Can be anything we don't really care, we only care about the K key existing
>(
source: Source,
key: K, // The key is of type K
destination: Destination,
transformer: (value: Source[K]) => Destination[K] // We use K to specify the relation between Source and Destination property type
) {
if (source[key] !== undefined) {
destination[key] = transformer ? transformer(source[key]) : source[key];
}
}
const a: A = { a: 123 };
const b: B = {};
copy(a, "a", b, (value) => value.toString());
copy(a, "a", b, (value) => value); /// error
Upvotes: 1