打字稿泛型:如何将数组条目映射到对象键
Typescript generics: Howto map array entries to object keys
TLDR:在我的通用函数中,我想要
myFunction(['width', 'left'])
到 return 类型 {width: string, left: string}
。
长版:
我有一个 Typescript 函数,它有一个字符串数组作为输入,returns 一个以数组的键作为值的对象:
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;
};
typescript return 值是 Object/Dictionary,但没有特定属性。
var resultObj = getStyle(document.body, ['width']);
resultObj.width; // should be ok
resultObj.height; // should be not ok
我尝试了很多东西。最棒的是那个:
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 现在从中得到了一个数组。我不知道为什么。
最后一次尝试也是 interface
,但 [index in P]
部分不起作用
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
您认为语法有点偏离,但您的想法非常接近。如果 P
是 string[]
那么 keyof P
只是数组的成员,而不是值。您可以使用 P[number]
来获取数组中值的类型。此外,接口不能包含映射类型([index in P]: ...
语法),只有类型别名可以(type
定义)。还有一个名为 Record
的预定义映射类型,这正是您所需要的,无需定义新类型
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
TLDR:在我的通用函数中,我想要
myFunction(['width', 'left'])
到 return 类型 {width: string, left: string}
。
长版:
我有一个 Typescript 函数,它有一个字符串数组作为输入,returns 一个以数组的键作为值的对象:
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;
};
typescript return 值是 Object/Dictionary,但没有特定属性。
var resultObj = getStyle(document.body, ['width']);
resultObj.width; // should be ok
resultObj.height; // should be not ok
我尝试了很多东西。最棒的是那个:
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 现在从中得到了一个数组。我不知道为什么。
最后一次尝试也是 interface
,但 [index in P]
部分不起作用
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
您认为语法有点偏离,但您的想法非常接近。如果 P
是 string[]
那么 keyof P
只是数组的成员,而不是值。您可以使用 P[number]
来获取数组中值的类型。此外,接口不能包含映射类型([index in P]: ...
语法),只有类型别名可以(type
定义)。还有一个名为 Record
的预定义映射类型,这正是您所需要的,无需定义新类型
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