Typescript, indexera en gränssnittsnyckel med en annan gränssnitt
Jag har två gränssnitt med identiska valfria nycklar, men olika värden:
interface Obj1 {
a?: string
b?: string
c?: number
}
interface Obj2 {
a: boolean
b: string
c: number
}
Obj1 används som ett funktionsargument, den andra, Obj2, är returvärdet av den funktionen. Jag vill att returtypen endast identifierar de angivna nycklarna på Obj1. Så om Obj1 endast innehöll a och b, kommer Obj2 också endast att innehålla a och b.
Jag försökte med tillvägagångssättet nedan, men jag får ett ts-fel Type 'Property' cannot be used to index type 'ValueType'
type Obj1KeysWithObj2Values<KeyType extends Obj1, ValueType extends Obj2> = {
[Property in keyof KeyType]: ValueType[Property]
}
UPPDATERING: Funktionen och dess anrop
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' })
Om du provar det, ser du på resultObj att du får vad du än skickar till funktionen, så länge det är i gränssnittet Obj1, oavsett Obj2.
Svar #1
Överväg att använda Pick<Type, Keys> som är en del av standardbiblioteket:
interface Obj1 {
a?: string
b?: string
c?: string
}
interface Obj2 {
a?: boolean
b?: boolean
c?: boolean
}
type Result = Pick<Obj2, keyof Obj1>
Det första argumentet representerar källobjektet, det andra argumentet representerar en förening av nycklar som ska väljas
I ditt fall behöver du också göra en snitt av Obj1-nycklar och Obj2-nycklar:
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' })
Lekplats
Svar #2
Problemet är att även om du vet att Obj2 alltid kommer att ha en superset av Obj1's nycklar, så vet inte TypeScript det, så det behöver bli försäkrat. :-) Om du vill använda de generiska typerna kan du rensa det felet genom att använda en villkorlig typ för att testa att egenskapsnyckeln också finns i ValueType:
type Obj1KeysWithObj2Values<KeyType extends Obj1, ValueType extends Obj2> = {
[Property in keyof KeyType]: Property extends keyof ValueType ? ValueType[Property] : never;
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
};
Lekplats exempel
