I have two interfaces with identical optional keys, but different values:
interface Obj1 {
a?: string
b?: string
c?: number
}
interface Obj2 {
a: boolean
b: string
c: number
}
Obj1 is served as a function argument, the other, Obj2, is the return of that function. I want the return type to identify only the given keys on Obj1. So if Obj1 contained only a and b then Obj2 will contain only a and b as well.
I tried with the approach bellow, but I get a ts error Type 'Property' cannot be used to index type 'ValueType'
type Obj1KeysWithObj2Values<KeyType extends Obj1, ValueType extends Obj2> = {
[Property in keyof KeyType]: ValueType[Property]
}
UPDATE: The function and its call
const myFunc = <T extends Obj1>({ a, b, c }: T) => {
const returnObj: Partial<Obj2> = {}
if (a) {
returnObj.a = true
}
if (b) {
returnObj.b = '1'
}
if (c) {
returnObj.c = 20
}
return returnObj as Obj1KeysWithObj2Values<T, Obj2>
}
const resultObj = myFunc({ a: 'hello', b: 'hello' })
If you try it, then you see on resultObj you get what ever you pass to the function, as long as it is in interface Obj1, regardless of Obj2.
Consider using Pick<Type, Keys> which is a part of standard library:
interface Obj1 {
a?: string
b?: string
c?: string
}
interface Obj2 {
a?: boolean
b?: boolean
c?: boolean
}
type Result = Pick<Obj2, keyof Obj1>
First argument represents source object, second argument represents a union of keys which should be picked
In your case, you also need to make an intersection of Obj1 keys and Obj2 keys:
interface Obj1 {
a?: string
b?: string
c?: number
}
interface Obj2 {
a: boolean
b: string
c: number
}
const myFunc = <T extends Obj1>({ a, b, c }: T) => {
const returnObj: Partial<Obj2> = {}
if (a) {
returnObj.a = true
}
if (b) {
returnObj.b = '1'
}
if (c) {
returnObj.c = 20
}
return returnObj as Pick<Obj2, keyof T & keyof Obj2>
}
const resultObj = myFunc({ a: 'hello', b: 'hello' })
Playground
The issue is that although you know that Obj2 will always have a superset of Obj1's keys, TypeScript doesn't know that, so it needs reassuring. :-) If you want to use those generics, you can clear that error by using a conditional type to test that the property key is also present in ValueType:
type Obj1KeysWithObj2Values<KeyType extends Obj1, ValueType extends Obj2> = {
[Property in keyof KeyType]: Property extends keyof ValueType ? ValueType[Property] : never;
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
};
Playground example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With