Získajte typ konkrétneho kľúča všeobecného typu v TypeScripte
Snažím sa získať funkcionalitu zložitého typu z tejto generickej funkcie updateArray, ktorú vytváram:
// Updates an object array at the specified update key with the update value,
// if the specified test key matches the test value.
// Optionally pass testFailValue to set a default value if the test fails.
// Note that by passing a testFailValue ALL elements in the array will be updated at the specified update property.
// If it is omitted only elements passing the test will be updated.
export const updateArray = <T, U, V>(options: {
array: Array<T>
testKey: keyof T
testValue: U
updateKey: keyof T
updateValue: V
testFailValue?: V
}): Array<T> => {
const {
array,
testKey,
testValue,
updateKey,
updateValue,
testFailValue,
} = options
return array.map(item => {
if (item[testKey] === testValue) {
item[updateKey] = updateValue
} else if (testFailValue !== undefined) {
item[updateKey] = testFailValue
}
return item
})
}
TypeScript tu bude hlásiť chybu ako v príklade if, tak aj v dvoch priraďovacích príkazoch, ale pri volaní podpisu funkcie nebude hlásiť chybu a je to presne tá prísna kontrola typov, ktorú hľadám, napríklad:
interface IMyInterface {
propertyA: string
prepertyB: boolean
}
updateArray<IMyInterface, IMyInterface['propertyA'], IMyInterface['propertyB']>({
array: state.editors[editor].editorSettings,
testKey: "propertyA",
testValue: 'someValue',
updateKey: "propertyB",
updateValue: true,
testFailValue: false
})
Ak vynechám typy U a V a nahradím ich T[keyof T], Typescript sa nebude sťažovať:
export const updateArray = <T>(options: {
array: Array<T>
testKey: keyof T
testValue: T[keyof T]
updateKey: keyof T
updateValue: T[keyof T]
testFailValue?: T[keyof T]
}): Array<T> => {
const {
array,
testKey,
testValue,
updateKey,
updateValue,
testFailValue,
} = options
return array.map(item => {
if (item[testKey] === testValue) {
item[updateKey] = updateValue
} else if (testFailValue !== undefined) {
item[updateKey] = testFailValue
}
return item
})
}
ale to tiež nie je úplne správne. T[keyof T] je príliš flexibilné: mohol by som priradiť „nesprávny“ typ k danej vlastnosti (napríklad v uvedenom príklade, boolean hodnotu k vlastnosti, ktorá by mala obsahovať iba reťazce, alebo naopak). Jasné, takéto priraďovanie typu je v poriadku v JavaScripte (čo je jeden z dôvodov, prečo TypeScript nebude robiť chybu), ale pre túto funkciu, ktorú vytváram, je to neželané. Skutočne potrebujem niečo ako typeof T[špecifický kľúč], aby som zabezpečil, že testValue, updateValue a testFailValue zodpovedajú správnym typom, pričom špecifický kľúč sa môže meniť v závislosti od skutočného typu T.
Môže sa niečo takéto urobiť?
Odpoveď č. 1
Môžete pridať obmedzenie na U, aby to bola podmnožina kľúčov T pomocou extends. V môže predstavovať typ updateKey a mať rovnaké obmedzenie.
Zjednodušením vášho problému na funkciu updateObject namiesto updateArray by to vyzeralo takto:
function updateObject<
T,
U extends keyof T,
V extends keyof T,
>(
obj: T,
testKey: U,
testValue: T[U],
updateKey: V,
updateValue: T[V],
testFailValue?: T[V]
) {
if (obj[testKey] === testValue) {
obj[updateKey] = updateValue;
} else if (testFailValue !== undefined) {
obj[updateKey] = testFailValue;
}
}
updateObject({aString: 'hello', aNumber: 42}, 'aString', 'hello', 'aNumber', 23);
