TLDR: In my generic function, i want to have
myFunction(['width', 'left'])
to return the type {width: string, left: string}
.
Long version:
I have an Typescript function which has an string array as an input and returns an object with keys of the array as a value:
export interface Dictionary<T> {
[index: string]: T | undefined;
}
var getStyle = function (
element: Element,
propertyNames: readonly string[]
) {
let gCS= window.getComputedStyle(element)
let result: Dictionary<string> = {};
propertyNames.forEach((prop)=>{
result[prop]=gCS.getPropertyValue(prop);
});
return result;
};
The typescript return value is a Object/Dictionary, but without specific properties.
var resultObj = getStyle(document.body, ['width']);
resultObj.width; // should be ok
resultObj.height; // should be not ok
I tried many things. The best thing was that one:
export type RestrictedDictionary1<T, P extends readonly string[]> = {
[index in keyof P]?: T | undefined
}
declare function getStyle1<P extends readonly string[]>(
element: Element,
propertyNames: P
): RestrictedDictionary1<string, P>;
var resultObj1 = getStyle1(document.body, ['width']); // Huh? Why an array
resultObj1.width; // should be ok, but both are unvalid for TS
resultObj1.height; // should be not ok, but both are unvalid for TS
Typescript now got an array from that. I have no idea why.
The last try is again an interface
, but the [index in P]
part does not work
export interface RestrictedDictionary2<T, P extends string[]> {
[index in P]: T | undefined; // A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.
}
declare function getStyle2<P extends string[]>(
element: Element,
propertyNames: P
): RestrictedDictionary2<string, P>;
var resultObj2 = getStyle2(document.body, ['width']);
resultObj2.width; // should be ok
resultObj2.height; // should be not ok
You are pretty close in your thinking the syntax is a bit off though. If P
is string[]
then the keyof P
are just the members of array, not the values. You could use P[number]
to get at the types of the values in the array. Also interfaces can't contain mapped types (the [index in P]: ...
syntax), only type aliases can (type
definitions). Also there is a predefined mapped type called Record
that is exactly what you need no need to define a new one
var getStyle = function<T extends string> (
element: Element,
propertyNames: readonly T[]
): Record<T, string> {
let gCS= window.getComputedStyle(element)
let result = {} as Record<T, string>;
propertyNames.forEach((prop)=>{
result[prop]=gCS.getPropertyValue(prop);
});
return result;
};
var resultObj = getStyle(document.body, ['width']);
resultObj.width; // should be ok
resultObj.height; // err
Play
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