rid
rid

Reputation: 63540

Key and value types in TypeScript

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:

Upvotes: 1

Views: 201

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

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

Related Questions